Introduce new volume dialog.
- New VolumeDialog (presentation) + VolumeDialogController (state) to implement a volume dialog that keeps track of multiple audio streams, including all remote streams. - The dialog starts out with a single stream, with more detail available behind an expand chevron. - Existing zen options reorganized under a master switch bar named "Block interruptions", with "None" renamed to "No interruptions" and "Priority" renamed to "Priority only". - Combined "Block interruptions" icon replaces the now-obsolete star/no-smoking icons in the status bar. - New icons for all sliders. - All sliders present a continuous facade, mapped to discrete integer units under the hood. - All interesting volume events and state changes piped through one central helper for future routing. - VolumePanel is obsolete, still accessible via a sysprop if needed. Complete removal / garbage collection deferred until all needed functionality is ported over. Bug: 19260237 Change-Id: I6689de3e4d14ae666d3e8da302cc9da2d4d77b9b
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
|
||||
<objectAnimator
|
||||
android:duration="250"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||
android:pathData="M 12.0,9.0 c 0.0,0.66667 0.0,5.0 0.0,6.0"
|
||||
android:propertyXName="translateX"
|
||||
android:propertyYName="translateY" />
|
||||
|
||||
</set>
|
||||
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
|
||||
<objectAnimator
|
||||
android:duration="200"
|
||||
android:interpolator="@interpolator/ic_volume_collapse_animation_interpolator_0"
|
||||
android:propertyName="rotation"
|
||||
android:valueFrom="45.0"
|
||||
android:valueTo="-45.0"
|
||||
android:valueType="floatType" />
|
||||
|
||||
</set>
|
||||
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
|
||||
<objectAnimator
|
||||
android:duration="200"
|
||||
android:interpolator="@interpolator/ic_volume_collapse_animation_interpolator_0"
|
||||
android:propertyName="rotation"
|
||||
android:valueFrom="-45.0"
|
||||
android:valueTo="45.0"
|
||||
android:valueType="floatType" />
|
||||
|
||||
</set>
|
||||
@@ -0,0 +1,25 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
|
||||
<objectAnimator
|
||||
android:duration="250"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||
android:pathData="M 12.0,15.0 c 0.0,-1.0 0.0,-5.33333 0.0,-6.0"
|
||||
android:propertyXName="translateX"
|
||||
android:propertyYName="translateY" />
|
||||
|
||||
</set>
|
||||
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
|
||||
<objectAnimator
|
||||
android:duration="200"
|
||||
android:interpolator="@interpolator/ic_volume_expand_animation_interpolator_0"
|
||||
android:propertyName="rotation"
|
||||
android:valueFrom="45.0"
|
||||
android:valueTo="-45.0"
|
||||
android:valueType="floatType" />
|
||||
|
||||
</set>
|
||||
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
|
||||
<objectAnimator
|
||||
android:duration="200"
|
||||
android:interpolator="@interpolator/ic_volume_expand_animation_interpolator_0"
|
||||
android:propertyName="rotation"
|
||||
android:valueFrom="-45.0"
|
||||
android:valueTo="45.0"
|
||||
android:valueType="floatType" />
|
||||
|
||||
</set>
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2014 The Android Open Source Project
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -13,13 +13,15 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="?android:attr/colorControlHighlight">
|
||||
android:color="?android:attr/colorControlHighlight" >
|
||||
|
||||
<item android:id="@android:id/mask">
|
||||
<shape>
|
||||
<corners android:radius="@dimen/borderless_button_radius" />
|
||||
|
||||
<solid android:color="@android:color/white" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
</ripple>
|
||||
26
packages/SystemUI/res/drawable/ic_dnd.xml
Normal file
26
packages/SystemUI/res/drawable/ic_dnd.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="48.0"
|
||||
android:viewportWidth="48.0"
|
||||
android:width="24dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M24.0,4.0C12.95,4.0 4.0,12.95 4.0,24.0s8.95,20.0 20.0,20.0 20.0,-8.95 20.0,-20.0S35.05,4.0 24.0,4.0zm10.0,22.0L14.0,26.0l0.0,-4.0l20.0,0.0l0.0,4.0z" />
|
||||
|
||||
</vector>
|
||||
@@ -1,25 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2014 The Android Open Source Project
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
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
|
||||
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.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48.0"
|
||||
android:viewportHeight="48.0">
|
||||
android:height="24.0dp"
|
||||
android:viewportHeight="48.0"
|
||||
android:viewportWidth="48.0"
|
||||
android:width="24.0dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M24.0,4.0C13.0,4.0 4.0,13.0 4.0,24.0s9.0,20.0 20.0,20.0c11.0,0.0 20.0,-9.0 20.0,-20.0S35.0,4.0 24.0,4.0zM34.0,26.0L14.0,26.0l0.0,-4.0l20.0,0.0L34.0,26.0z"/>
|
||||
</vector>
|
||||
android:pathData="M38.0,26.0L10.0,26.0l0.0,-4.0l28.0,0.0l0.0,4.0z" />
|
||||
|
||||
</vector>
|
||||
@@ -1,25 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2014 The Android Open Source Project
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
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
|
||||
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.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48.0"
|
||||
android:viewportHeight="48.0">
|
||||
android:height="24.0dp"
|
||||
android:viewportHeight="48.0"
|
||||
android:viewportWidth="48.0"
|
||||
android:width="24.0dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M24.0,4.0C13.0,4.0 4.0,13.0 4.0,24.0s9.0,20.0 20.0,20.0c11.0,0.0 20.0,-9.0 20.0,-20.0S35.0,4.0 24.0,4.0zM34.0,26.0l-8.0,0.0l0.0,8.0l-4.0,0.0l0.0,-8.0l-8.0,0.0l0.0,-4.0l8.0,0.0l0.0,-8.0l4.0,0.0l0.0,8.0l8.0,0.0L34.0,26.0z"/>
|
||||
</vector>
|
||||
android:pathData="M38.0,26.0L26.0,26.0l0.0,12.0l-4.0,0.0L22.0,26.0L10.0,26.0l0.0,-4.0l12.0,0.0L22.0,10.0l4.0,0.0l0.0,12.0l12.0,0.0l0.0,4.0z" />
|
||||
|
||||
</vector>
|
||||
26
packages/SystemUI/res/drawable/ic_volume_alarm.xml
Normal file
26
packages/SystemUI/res/drawable/ic_volume_alarm.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24.0dp"
|
||||
android:viewportHeight="48.0"
|
||||
android:viewportWidth="48.0"
|
||||
android:width="24.0dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M44.0,11.44l-9.19,-7.71 -2.57,3.06 9.19,7.71 2.57,-3.06zm-28.24,-4.66l-2.57,-3.06 -9.19,7.71 2.57,3.06 9.19,-7.71zm9.24,9.22l-3.0,0.0l0.0,12.0l9.49,5.71 1.51,-2.47 -8.0,-4.74l0.0,-10.5zm-1.01,-8.0c-9.95,0.0 -17.99,8.06 -17.99,18.0s8.04,18.0 17.99,18.0 18.01,-8.06 18.01,-18.0 -8.06,-18.0 -18.01,-18.0zm0.01,32.0c-7.73,0.0 -14.0,-6.27 -14.0,-14.0s6.27,-14.0 14.0,-14.0 14.0,6.27 14.0,14.0 -6.26,14.0 -14.0,14.0z" />
|
||||
|
||||
</vector>
|
||||
26
packages/SystemUI/res/drawable/ic_volume_alarm_mute.xml
Normal file
26
packages/SystemUI/res/drawable/ic_volume_alarm_mute.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24.0dp"
|
||||
android:viewportHeight="48.0"
|
||||
android:viewportWidth="48.0"
|
||||
android:width="24.0dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M24.0,12.0c7.73,0.0 14.0,6.27 14.0,14.0 0.0,1.69 -0.31,3.3 -0.86,4.8l3.04,3.04c1.16,-2.37 1.82,-5.03 1.82,-7.84 0.0,-9.94 -8.06,-18.0 -18.01,-18.0 -2.81,0.0 -5.46,0.66 -7.84,1.81l3.05,3.05c1.5,-0.55 3.11,-0.86 4.8,-0.86zm20.0,-0.56l-9.19,-7.71 -2.57,3.06 9.19,7.71 2.57,-3.06zm-38.16,-6.85l-2.55,2.54 2.66,2.66 -2.22,1.86 2.84,2.84 2.22,-1.86 1.6,1.6c-2.73,3.16 -4.39,7.27 -4.39,11.77 0.0,9.94 8.04,18.0 17.99,18.0 4.51,0.0 8.62,-1.67 11.77,-4.4l4.4,4.4 2.54,-2.55 -34.91,-34.91 -1.95,-1.95zm27.1,32.19c-2.43,2.01 -5.54,3.22 -8.94,3.22 -7.73,0.0 -14.0,-6.27 -14.0,-14.0 0.0,-3.4 1.21,-6.51 3.22,-8.94l19.72,19.72zm-16.91,-30.23l-2.84,-2.84 -1.7,1.43 2.84,2.84 1.7,-1.43z" />
|
||||
|
||||
</vector>
|
||||
26
packages/SystemUI/res/drawable/ic_volume_bt.xml
Normal file
26
packages/SystemUI/res/drawable/ic_volume_bt.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="48.0"
|
||||
android:viewportWidth="48.0"
|
||||
android:width="24dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M35.4,15.4L24.0,4.0l-2.0,0.0l0.0,15.2L12.8,10.0L10.0,12.8L21.2,24.0L10.0,35.2l2.8,2.8l9.2,-9.2L22.0,44.0l2.0,0.0l11.4,-11.4L26.8,24.0L35.4,15.4zM26.0,11.7l3.8,3.8L26.0,19.2L26.0,11.7zM29.8,32.6L26.0,36.3l0.0,-7.5L29.8,32.6z" />
|
||||
|
||||
</vector>
|
||||
26
packages/SystemUI/res/drawable/ic_volume_bt_mute.xml
Normal file
26
packages/SystemUI/res/drawable/ic_volume_bt_mute.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="48.0"
|
||||
android:viewportWidth="48.0"
|
||||
android:width="24dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M26.0,11.8l3.8,3.8l-3.2,3.2l2.8,2.8l6.0,-6.0L24.0,4.2l-2.0,0.0l0.0,10.1l4.0,4.0L26.0,11.8zM10.8,8.2L8.0,11.0l13.2,13.2L10.0,35.3l2.8,2.8L22.0,29.0l0.0,15.2l2.0,0.0l8.6,-8.6l4.6,4.6l2.8,-2.8L10.8,8.2zM26.0,36.5L26.0,29.0l3.8,3.8L26.0,36.5z" />
|
||||
|
||||
</vector>
|
||||
26
packages/SystemUI/res/drawable/ic_volume_bt_sco.xml
Normal file
26
packages/SystemUI/res/drawable/ic_volume_bt_sco.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24.0dp"
|
||||
android:viewportHeight="48.0"
|
||||
android:viewportWidth="48.0"
|
||||
android:width="24.0dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M29.41,19.0L34.0,14.41L34.0,22.0l1.0,0.0l5.71,-5.71 -4.3,-4.29 4.29,-4.29L35.0,2.0l-1.0,0.0l0.0,7.59L29.41,5.0 28.0,6.41 33.59,12.0 28.0,17.59 29.41,19.0zM36.0,5.83l1.88,1.88L36.0,9.59L36.0,5.83zm0.0,8.58l1.88,1.88L36.0,18.17l0.0,-3.76zM40.0,31.0c-2.49,0.0 -4.89,-0.4 -7.14,-1.14 -0.69,-0.22 -1.48,-0.06 -2.0,0.49l-4.4,4.41c-5.67,-2.88 -10.29,-7.51 -13.18,-13.17l4.4,-4.41c0.55,-0.5 0.71,-1.3 0.49,-2.03C17.4,12.9 17.0,10.49 17.0,8.0c0.0,-1.11 -0.89,-2.0 -2.0,-2.0L8.0,6.0c-1.11,0.0 -2.0,0.89 -2.0,2.0 0.0,18.78 15.22,34.0 34.0,34.0 1.11,0.0 2.0,-0.89 2.0,-2.0l0.0,-7.0c0.0,-1.11 -0.89,-2.0 -2.0,-2.0z" />
|
||||
|
||||
</vector>
|
||||
62
packages/SystemUI/res/drawable/ic_volume_collapse.xml
Normal file
62
packages/SystemUI/res/drawable/ic_volume_collapse.xml
Normal file
@@ -0,0 +1,62 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:name="ic_volume_collapse"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24"
|
||||
android:width="24dp" >
|
||||
|
||||
<group
|
||||
android:name="chevron_02"
|
||||
android:rotation="90"
|
||||
android:translateX="12"
|
||||
android:translateY="9" >
|
||||
<group
|
||||
android:name="rectangle_2"
|
||||
android:rotation="-45" >
|
||||
<group
|
||||
android:name="rectangle_2_pivot"
|
||||
android:translateY="4" >
|
||||
<group
|
||||
android:name="rectangle_path_2_position"
|
||||
android:translateY="-1" >
|
||||
<path
|
||||
android:name="rectangle_path_2"
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M -1.0,-4.0 l 2.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,8.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -2.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-8.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group
|
||||
android:name="rectangle_1"
|
||||
android:rotation="45" >
|
||||
<group
|
||||
android:name="rectangle_1_pivot"
|
||||
android:translateY="-4" >
|
||||
<group
|
||||
android:name="rectangle_path_1_position"
|
||||
android:translateY="1" >
|
||||
<path
|
||||
android:name="rectangle_path_1"
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M -1.0,-4.0 l 2.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,8.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -2.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-8.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,29 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:drawable="@drawable/ic_volume_collapse" >
|
||||
|
||||
<target
|
||||
android:name="chevron_02"
|
||||
android:animation="@anim/ic_volume_collapse_chevron_02_animation" />
|
||||
<target
|
||||
android:name="rectangle_2"
|
||||
android:animation="@anim/ic_volume_collapse_rectangle_2_animation" />
|
||||
<target
|
||||
android:name="rectangle_1"
|
||||
android:animation="@anim/ic_volume_collapse_rectangle_1_animation" />
|
||||
|
||||
</animated-vector>
|
||||
62
packages/SystemUI/res/drawable/ic_volume_expand.xml
Normal file
62
packages/SystemUI/res/drawable/ic_volume_expand.xml
Normal file
@@ -0,0 +1,62 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:name="ic_volume_expand"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24"
|
||||
android:width="24dp" >
|
||||
|
||||
<group
|
||||
android:name="chevron_01"
|
||||
android:rotation="90"
|
||||
android:translateX="12"
|
||||
android:translateY="15" >
|
||||
<group
|
||||
android:name="rectangle_3"
|
||||
android:rotation="45" >
|
||||
<group
|
||||
android:name="rectangle_2_pivot_0"
|
||||
android:translateY="4" >
|
||||
<group
|
||||
android:name="rectangle_path_3_position"
|
||||
android:translateY="-1" >
|
||||
<path
|
||||
android:name="rectangle_path_3"
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M -1.0,-4.0 l 2.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,8.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -2.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-8.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group
|
||||
android:name="rectangle_4"
|
||||
android:rotation="-45" >
|
||||
<group
|
||||
android:name="rectangle_1_pivot_0"
|
||||
android:translateY="-4" >
|
||||
<group
|
||||
android:name="rectangle_path_4_position"
|
||||
android:translateY="1" >
|
||||
<path
|
||||
android:name="rectangle_path_4"
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M -1.0,-4.0 l 2.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,8.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -2.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-8.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,29 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:drawable="@drawable/ic_volume_expand" >
|
||||
|
||||
<target
|
||||
android:name="chevron_01"
|
||||
android:animation="@anim/ic_volume_expand_chevron_01_animation" />
|
||||
<target
|
||||
android:name="rectangle_3"
|
||||
android:animation="@anim/ic_volume_expand_rectangle_3_animation" />
|
||||
<target
|
||||
android:name="rectangle_4"
|
||||
android:animation="@anim/ic_volume_expand_rectangle_4_animation" />
|
||||
|
||||
</animated-vector>
|
||||
26
packages/SystemUI/res/drawable/ic_volume_media.xml
Normal file
26
packages/SystemUI/res/drawable/ic_volume_media.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24.0dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24.0dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M12.0,3.0l0.0,9.28c-0.47,-0.17 -0.97,-0.28 -1.5,-0.28C8.01,12.0 6.0,14.01 6.0,16.5S8.01,21.0 10.5,21.0c2.31,0.0 4.2,-1.75 4.45,-4.0L15.0,17.0L15.0,6.0l4.0,0.0L19.0,3.0l-7.0,0.0z" />
|
||||
|
||||
</vector>
|
||||
29
packages/SystemUI/res/drawable/ic_volume_media_mute.xml
Normal file
29
packages/SystemUI/res/drawable/ic_volume_media_mute.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24.0dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24.0dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M15.0,6.0l4.0,0.0L19.0,3.0l-7.0,0.0l0.0,5.6l3.0,3.0C15.0,8.8 15.0,6.0 15.0,6.0z" />
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M4.8,3.9L3.5,5.1l6.9,6.9C8.0,12.1 6.0,14.0 6.0,16.5C6.0,19.0 8.0,21.0 10.5,21.0c2.7,0.0 4.5,-2.3 4.5,-4.3c0.0,0.0 0.0,-0.1 0.0,-0.1l4.0,4.0l1.3,-1.3L4.8,3.9z" />
|
||||
|
||||
</vector>
|
||||
26
packages/SystemUI/res/drawable/ic_volume_remote.xml
Normal file
26
packages/SystemUI/res/drawable/ic_volume_remote.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="48.0"
|
||||
android:viewportWidth="48.0"
|
||||
android:width="24dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M2.0,36.0l0.0,6.0l6.0,0.0C8.0,38.7 5.3,36.0 2.0,36.0zM2.0,28.0l0.0,4.0c5.5,0.0 10.0,4.5 10.0,10.0l4.0,0.0C16.0,34.3 9.7,28.0 2.0,28.0zM38.0,14.0L10.0,14.0l0.0,3.3c7.9,2.6 14.2,8.8 16.7,16.7L38.0,34.0L38.0,14.0zM2.0,20.0l0.0,4.0c9.9,0.0 18.0,8.1 18.0,18.0l4.0,0.0C24.0,29.8 14.1,20.0 2.0,20.0zM42.0,6.0L6.0,6.0c-2.2,0.0 -4.0,1.8 -4.0,4.0l0.0,6.0l4.0,0.0l0.0,-6.0l36.0,0.0l0.0,28.0L28.0,38.0l0.0,4.0l14.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L46.0,10.0C46.0,7.8 44.2,6.0 42.0,6.0z" />
|
||||
|
||||
</vector>
|
||||
38
packages/SystemUI/res/drawable/ic_volume_remote_mute.xml
Normal file
38
packages/SystemUI/res/drawable/ic_volume_remote_mute.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24.0dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24.0dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M23.7,21.3l-1.1,-1.0c0.0,0.0 0.0,0.0 0.0,0.0L21.0,18.8l0.0,0.0L5.8,5.0l0.0,0.0L3.6,3.0l0.0,0.0L1.7,1.3L0.3,2.7l1.1,1.0C1.2,4.1 1.0,4.5 1.0,5.0l0.0,3.0l2.0,0.0L3.0,5.2L18.2,19.0L14.0,19.0l0.0,2.0l6.4,0.0l1.9,1.7L23.7,21.3z" />
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M21.0,5.0l0.0,11.1l2.0,1.8L23.0,5.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0L6.6,3.0l2.2,2.0L21.0,5.0z" />
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M1.0,18.0l0.0,3.0l3.0,0.0C4.0,19.3 2.7,18.0 1.0,18.0z" />
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M1.0,14.0l0.0,2.0c2.8,0.0 5.0,2.2 5.0,5.0l2.0,0.0C8.0,17.1 4.9,14.0 1.0,14.0z" />
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M1.0,10.0l0.0,2.0c5.0,0.0 9.0,4.0 9.0,9.0l2.0,0.0C12.0,14.9 7.1,10.0 1.0,10.0z" />
|
||||
|
||||
</vector>
|
||||
26
packages/SystemUI/res/drawable/ic_volume_ringer.xml
Normal file
26
packages/SystemUI/res/drawable/ic_volume_ringer.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
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>
|
||||
26
packages/SystemUI/res/drawable/ic_volume_ringer_mute.xml
Normal file
26
packages/SystemUI/res/drawable/ic_volume_ringer_mute.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="48.0"
|
||||
android:viewportWidth="48.0"
|
||||
android:width="24dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M23.000000,44.000000c2.200000,0.000000 4.000000,-1.800000 4.000000,-4.000000l-8.000000,0.000000C19.000000,42.200001 20.799999,44.000000 23.000000,44.000000zM36.000000,21.000000c0.000000,-6.100000 -4.300000,-11.300000 -10.000000,-12.600000L26.000000,7.000000c0.000000,-1.700000 -1.300000,-3.000000 -3.000000,-3.000000c-1.700000,0.000000 -3.000000,1.300000 -3.000000,3.000000l0.000000,1.400000c-1.000000,0.200000 -2.000000,0.600000 -2.900000,1.100000L36.000000,28.400000L36.000000,21.000000zM35.500000,38.000000l4.000000,4.000000l2.500000,-2.500000L8.500000,6.000000L6.000000,8.500000l5.800000,5.800000C10.700000,16.299999 10.000000,18.600000 10.000000,21.000000l0.000000,11.000000l-4.000000,4.000000l0.000000,2.000000L35.500000,38.000000z" />
|
||||
|
||||
</vector>
|
||||
26
packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
Normal file
26
packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
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>
|
||||
26
packages/SystemUI/res/drawable/ic_volume_settings.xml
Normal file
26
packages/SystemUI/res/drawable/ic_volume_settings.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="20dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="20dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="@color/volume_settings_icon_color"
|
||||
android:pathData="M19.4,13.0c0.0,-0.3 0.1,-0.6 0.1,-1.0s0.0,-0.7 -0.1,-1.0l2.1,-1.7c0.2,-0.2 0.2,-0.4 0.1,-0.6l-2.0,-3.5C19.5,5.1 19.3,5.0 19.0,5.1l-2.5,1.0c-0.5,-0.4 -1.1,-0.7 -1.7,-1.0l-0.4,-2.6C14.5,2.2 14.2,2.0 14.0,2.0l-4.0,0.0C9.8,2.0 9.5,2.2 9.5,2.4L9.1,5.1C8.5,5.3 8.0,5.7 7.4,6.1L5.0,5.1C4.7,5.0 4.5,5.1 4.3,5.3l-2.0,3.5C2.2,8.9 2.3,9.2 2.5,9.4L4.6,11.0c0.0,0.3 -0.1,0.6 -0.1,1.0s0.0,0.7 0.1,1.0l-2.1,1.7c-0.2,0.2 -0.2,0.4 -0.1,0.6l2.0,3.5C4.5,18.9 4.7,19.0 5.0,18.9l2.5,-1.0c0.5,0.4 1.1,0.7 1.7,1.0l0.4,2.6c0.0,0.2 0.2,0.4 0.5,0.4l4.0,0.0c0.2,0.0 0.5,-0.2 0.5,-0.4l0.4,-2.6c0.6,-0.3 1.2,-0.6 1.7,-1.0l2.5,1.0c0.2,0.1 0.5,0.0 0.6,-0.2l2.0,-3.5c0.1,-0.2 0.1,-0.5 -0.1,-0.6L19.4,13.0zM12.0,15.5c-1.9,0.0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S13.9,15.5 12.0,15.5z" />
|
||||
|
||||
</vector>
|
||||
32
packages/SystemUI/res/drawable/ic_volume_system.xml
Normal file
32
packages/SystemUI/res/drawable/ic_volume_system.xml
Normal file
@@ -0,0 +1,32 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24.0dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24.0dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M17.7,14.8l-4.5,-2.3c-0.2,-0.1 -0.4,-0.1 -0.5,-0.1l-0.8,0.0l0.0,-6.0c0.0,-0.8 -0.7,-1.5 -1.5,-1.5S8.9,5.6 8.9,6.4l0.0,10.7l-3.4,-0.7c-0.1,0.0 -0.2,0.0 -0.2,0.0c-0.3,0.0 -0.6,0.1 -0.8,0.3l-0.8,0.8l4.9,4.9c0.3,0.3 0.6,0.4 1.1,0.4l6.8,0.0c0.8,0.0 1.3,-0.6 1.4,-1.3l0.8,-5.3c0.0,-0.1 0.0,-0.1 0.0,-0.2C18.6,15.5 18.2,15.0 17.7,14.8z" />
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M14.3,8.8l1.8,0.9c1.5,-2.0 1.4,-4.8 -0.4,-6.6l-1.4,1.4C15.5,5.7 15.5,7.6 14.3,8.8z" />
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M17.9,10.6l1.8,0.9C22.0,8.0 21.6,3.3 18.5,0.3l-1.4,1.4C19.5,4.1 19.8,7.9 17.9,10.6z" />
|
||||
|
||||
</vector>
|
||||
35
packages/SystemUI/res/drawable/ic_volume_system_mute.xml
Normal file
35
packages/SystemUI/res/drawable/ic_volume_system_mute.xml
Normal file
@@ -0,0 +1,35 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24.0dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24.0dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M14.3,8.8l1.8,0.9c1.5,-2.0 1.4,-4.8 -0.4,-6.6l-1.4,1.4C15.5,5.7 15.5,7.6 14.3,8.8z" />
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M17.9,10.6l1.8,0.9C22.0,8.0 21.6,3.3 18.5,0.3l-1.4,1.4C19.5,4.1 19.8,7.9 17.9,10.6z" />
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M22.0,20.6l-3.5,-2.8l0.0,0.0l-9.6,-7.6l0.0,0.0L3.2,5.7L2.0,7.3l6.9,5.4L8.9,17.0l-3.4,-0.7c-0.1,0.0 -0.2,0.0 -0.2,0.0c-0.3,0.0 -0.6,0.1 -0.8,0.3l-0.8,0.8l4.9,4.9c0.3,0.3 0.6,0.4 1.1,0.4l6.8,0.0c0.8,0.0 1.3,-0.6 1.4,-1.3l0.2,-1.5l2.6,2.1L22.0,20.6z" />
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M11.9,6.4c0.0,-0.8 -0.7,-1.5 -1.5,-1.5S8.9,5.6 8.9,6.4l0.0,1.5l3.0,2.4L11.9,6.4z" />
|
||||
|
||||
</vector>
|
||||
26
packages/SystemUI/res/drawable/ic_volume_voice.xml
Normal file
26
packages/SystemUI/res/drawable/ic_volume_voice.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24.0dp"
|
||||
android:viewportHeight="48.0"
|
||||
android:viewportWidth="48.0"
|
||||
android:width="24.0dp" >
|
||||
|
||||
<path
|
||||
android:fillColor="@color/volume_icon_color"
|
||||
android:pathData="M13.25,21.59c2.88,5.66 7.51,10.29 13.18,13.17l4.4,-4.41c0.55,-0.55 1.34,-0.71 2.03,-0.49C35.1,30.6 37.51,31.0 40.0,31.0c1.11,0.0 2.0,0.89 2.0,2.0l0.0,7.0c0.0,1.11 -0.89,2.0 -2.0,2.0C21.22,42.0 6.0,26.78 6.0,8.0c0.0,-1.1 0.9,-2.0 2.0,-2.0l7.0,0.0c1.11,0.0 2.0,0.89 2.0,2.0 0.0,2.4 0.4,4.9 1.14,7.1 0.2,0.6 0.06,1.48 -0.49,2.03l-4.4,4.42z" />
|
||||
|
||||
</vector>
|
||||
22
packages/SystemUI/res/drawable/volume_dialog_background.xml
Normal file
22
packages/SystemUI/res/drawable/volume_dialog_background.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
|
||||
<solid android:color="@color/system_primary_color" />
|
||||
|
||||
<corners android:radius="@dimen/notification_material_rounded_rect_radius" />
|
||||
|
||||
</shape>
|
||||
@@ -0,0 +1,17 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:pathData="M 0.0,0.0 c 0.0001,0.0 0.0,1.0 1.0,1.0" />
|
||||
@@ -0,0 +1,17 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:pathData="M 0.0,0.0 c 0.0001,0.0 0.0,1.0 1.0,1.0" />
|
||||
@@ -19,10 +19,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/segmented_button_spacing"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center_horizontal|top"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/segmented_button_text_selector"
|
||||
android:background="@drawable/btn_borderless_rect"
|
||||
android:textAppearance="@style/TextAppearance.QS.SegmentedButton"
|
||||
android:minHeight="64dp"
|
||||
android:paddingTop="11dp"
|
||||
android:drawablePadding="6dp" />
|
||||
android:textAppearance="@style/TextAppearance.Volume.ZenSwitchSummary"
|
||||
android:minHeight="48dp" />
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2014 The Android Open Source Project
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -14,15 +13,50 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/volume_dialog"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginLeft="@dimen/notification_side_padding"
|
||||
android:layout_marginRight="@dimen/notification_side_padding"
|
||||
android:background="@drawable/qs_background_primary"
|
||||
android:translationZ="@dimen/volume_panel_z"
|
||||
android:layout_marginBottom="@dimen/volume_panel_z">
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="@drawable/volume_dialog_background"
|
||||
android:translationZ="4dp" >
|
||||
|
||||
<include layout="@layout/volume_panel" />
|
||||
<com.android.keyguard.AlphaOptimizedImageButton
|
||||
android:id="@+id/volume_expand_button"
|
||||
style="@style/VolumeButtons"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_width="@dimen/volume_button_size"
|
||||
android:layout_height="@dimen/volume_button_size"
|
||||
android:clickable="true"
|
||||
android:soundEffectsEnabled="false"
|
||||
android:src="@drawable/ic_volume_collapse_animation" />
|
||||
|
||||
</FrameLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/volume_dialog_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingTop="6dp" >
|
||||
|
||||
<!-- volume rows added and removed here! :-) -->
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/volume_footer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:ignore="UselessParent" >
|
||||
|
||||
<include layout="@layout/volume_text_footer" />
|
||||
|
||||
<include layout="@layout/volume_zen_footer" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
64
packages/SystemUI/res/layout/volume_dialog_row.xml
Normal file
64
packages/SystemUI/res/layout/volume_dialog_row.xml
Normal file
@@ -0,0 +1,64 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/volume_row_header"
|
||||
style="?android:attr/textAppearanceButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="@dimen/volume_secondary_alpha"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:paddingBottom="0dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingStart="13dp"
|
||||
android:paddingTop="8dp" />
|
||||
|
||||
<com.android.keyguard.AlphaOptimizedImageButton
|
||||
android:id="@+id/volume_row_icon"
|
||||
style="@style/VolumeButtons"
|
||||
android:layout_width="@dimen/volume_button_size"
|
||||
android:layout_height="@dimen/volume_button_size"
|
||||
android:layout_below="@id/volume_row_header"
|
||||
android:soundEffectsEnabled="false" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/volume_row_slider"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBottom="@+id/volume_row_icon"
|
||||
android:layout_alignWithParentIfMissing="true"
|
||||
android:layout_below="@id/volume_row_header"
|
||||
android:layout_toEndOf="@id/volume_row_icon"
|
||||
android:layout_toStartOf="@+id/volume_settings_button"
|
||||
android:paddingEnd="4dp"
|
||||
android:paddingStart="4dp"
|
||||
android:progressTint="@android:color/white"
|
||||
android:thumbTint="@android:color/white" />
|
||||
|
||||
<com.android.keyguard.AlphaOptimizedImageButton
|
||||
android:id="@+id/volume_settings_button"
|
||||
style="@style/VolumeButtons"
|
||||
android:layout_width="@dimen/volume_button_size"
|
||||
android:layout_height="@dimen/volume_button_size"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_below="@id/volume_row_header" />
|
||||
|
||||
</RelativeLayout>
|
||||
27
packages/SystemUI/res/layout/volume_panel_dialog.xml
Normal file
27
packages/SystemUI/res/layout/volume_panel_dialog.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/volume_panel_z"
|
||||
android:layout_marginLeft="@dimen/notification_side_padding"
|
||||
android:layout_marginRight="@dimen/notification_side_padding"
|
||||
android:background="@drawable/qs_background_primary"
|
||||
android:translationZ="@dimen/volume_panel_z" >
|
||||
|
||||
<include layout="@layout/volume_panel" />
|
||||
|
||||
</FrameLayout>
|
||||
54
packages/SystemUI/res/layout/volume_text_footer.xml
Normal file
54
packages/SystemUI/res/layout/volume_text_footer.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/volume_text_footer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
tools:ignore="UselessParent" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/volume_footline_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBaseline="@+id/volume_footline_action_button"
|
||||
android:alpha="@dimen/volume_secondary_alpha"
|
||||
android:fontFamily="sans-serif"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingStart="13dp"
|
||||
android:textColor="?android:attr/textColorPrimary" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/volume_footline_action_button"
|
||||
style="@android:style/Widget.Material.Button.Borderless"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/volume_button_size"
|
||||
android:layout_toEndOf="@id/volume_footline_text"
|
||||
android:layout_toStartOf="@+id/volume_settings_button"
|
||||
android:alpha="@dimen/volume_secondary_alpha"
|
||||
android:paddingEnd="0dp"
|
||||
android:paddingStart="0dp" />
|
||||
|
||||
<com.android.keyguard.AlphaOptimizedImageButton
|
||||
android:id="@+id/volume_settings_button"
|
||||
style="@style/VolumeButtons"
|
||||
android:layout_width="@dimen/volume_button_size"
|
||||
android:layout_height="@dimen/volume_button_size"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:src="@drawable/ic_volume_settings" />
|
||||
|
||||
</RelativeLayout>
|
||||
108
packages/SystemUI/res/layout/volume_zen_footer.xml
Normal file
108
packages/SystemUI/res/layout/volume_zen_footer.xml
Normal file
@@ -0,0 +1,108 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<com.android.systemui.volume.ZenFooter xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/volume_zen_footer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" > <!-- extends LinearLayout -->
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/volume_zen_switch_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/volume_button_size"
|
||||
android:clickable="true"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/volume_zen_switch_bar_icon"
|
||||
android:layout_width="@dimen/volume_button_size"
|
||||
android:layout_height="@dimen/volume_button_size"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_dnd" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center_vertical"
|
||||
android:textDirection="locale"
|
||||
android:padding="3dp"
|
||||
android:text="@string/volume_zen_switch_text"
|
||||
android:textAppearance="@style/TextAppearance.Volume.ZenSwitch" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/volume_zen_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_marginEnd="11dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/volume_zen_panel_summary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/volume_button_size"
|
||||
android:layout_marginStart="@dimen/volume_button_size"
|
||||
android:paddingEnd="3dp"
|
||||
android:paddingStart="3dp" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/volume_zen_panel_summary_line_1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.Volume.ZenSwitchSummary" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/volume_zen_panel_summary_line_2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/volume_zen_panel_summary_line_1"
|
||||
android:textAppearance="@style/TextAppearance.Volume.ZenSwitchDetail" />
|
||||
</RelativeLayout>
|
||||
|
||||
<include layout="@layout/zen_mode_panel" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/volume_zen_mode_panel_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/volume_zen_mode_panel_more"
|
||||
style="@style/QSBorderlessButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:minWidth="132dp"
|
||||
android:text="@string/quick_settings_more_settings"
|
||||
android:textAppearance="@style/TextAppearance.QS.DetailButton" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/volume_zen_mode_panel_done"
|
||||
style="@style/QSBorderlessButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:minWidth="84dp"
|
||||
android:text="@string/quick_settings_done"
|
||||
android:textAppearance="@style/TextAppearance.QS.DetailButton" />
|
||||
</LinearLayout>
|
||||
|
||||
</com.android.systemui.volume.ZenFooter>
|
||||
@@ -34,8 +34,8 @@
|
||||
android:id="@+id/zen_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_marginLeft="40dp"
|
||||
android:layout_marginRight="40dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:clipChildren="false" />
|
||||
</FrameLayout>
|
||||
|
||||
@@ -758,10 +758,10 @@
|
||||
<string name="camera_hint">Swipe left for camera</string>
|
||||
|
||||
<!-- Interruption level: None. [CHAR LIMIT=20] -->
|
||||
<string name="interruption_level_none">None</string>
|
||||
<string name="interruption_level_none">No interruptions</string>
|
||||
|
||||
<!-- Interruption level: Priority. [CHAR LIMIT=20] -->
|
||||
<string name="interruption_level_priority">Priority</string>
|
||||
<string name="interruption_level_priority">Priority only</string>
|
||||
|
||||
<!-- Interruption level: All. [CHAR LIMIT=20] -->
|
||||
<string name="interruption_level_all">All</string>
|
||||
@@ -965,4 +965,7 @@
|
||||
|
||||
<!-- VolumeUI restoration notification: text -->
|
||||
<string name="volumeui_notification_text">Touch to restore the original.</string>
|
||||
|
||||
<!-- Volume dialog zen toggle switch title -->
|
||||
<string name="volume_zen_switch_text">Block interruptions</string>
|
||||
</resources>
|
||||
|
||||
87
packages/SystemUI/res/values/volume.xml
Normal file
87
packages/SystemUI/res/values/volume.xml
Normal file
@@ -0,0 +1,87 @@
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item name="volume_expand_animation_duration" type="integer">300</item>
|
||||
|
||||
<color name="volume_icon_color">#ffffffff</color>
|
||||
<color name="volume_settings_icon_color">#7fffffff</color>
|
||||
|
||||
<dimen name="volume_slider_interspacing">2dp</dimen>
|
||||
<dimen name="volume_offset_top">0dp</dimen>
|
||||
<dimen name="volume_button_size">48dp</dimen>
|
||||
|
||||
<item name="volume_secondary_alpha" format="float" type="dimen">0.3</item>
|
||||
|
||||
<style name="VolumeDialogAnimations">
|
||||
<item name="android:windowEnterAnimation">@android:anim/fade_in</item>
|
||||
<item name="android:windowExitAnimation">@android:anim/fade_out</item>
|
||||
</style>
|
||||
|
||||
<style name="VolumeButtons" parent="@android:style/Widget.Material.Button.Borderless">
|
||||
<item name="android:background">@drawable/btn_borderless_rect</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance" />
|
||||
|
||||
<style name="TextAppearance.Volume">
|
||||
<item name="android:textStyle">normal</item>
|
||||
<item name="android:textColor">#ffffffff</item>
|
||||
<item name="android:fontFamily">sans-serif</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.Volume.ZenSwitch">
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:fontFamily">sans-serif-medium</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.Volume.ZenSwitchSummary">
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:fontFamily">sans-serif-medium</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.Volume.ZenSwitchDetail">
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:fontFamily">sans-serif</item>
|
||||
<item name="android:textColor">#ffb0b3c5</item>
|
||||
</style>
|
||||
|
||||
<string-array name="volume_stream_titles" translatable="false">
|
||||
<item>Voice calls</item> <!-- STREAM_VOICE_CALL -->
|
||||
<item>System</item> <!-- STREAM_SYSTEM -->
|
||||
<item>Notifications</item> <!-- STREAM_RING -->
|
||||
<item>Media</item> <!-- STREAM_MUSIC -->
|
||||
<item>Alarms</item> <!-- STREAM_ALARM -->
|
||||
<item></item> <!-- STREAM_NOTIFICATION -->
|
||||
<item>Bluetooth calls</item> <!-- STREAM_BLUETOOTH_SCO -->
|
||||
<item></item> <!-- STREAM_SYSTEM_ENFORCED -->
|
||||
<item></item> <!-- STREAM_DTMF -->
|
||||
<item></item> <!-- STREAM_TTS -->
|
||||
</string-array>
|
||||
|
||||
<string name="volume_dnd_is_on" translatable="false">Do not disturb is on</string>
|
||||
<string name="volume_turn_off" translatable="false">Turn off</string>
|
||||
<string name="volume_stream_muted" translatable="false">%s silent</string>
|
||||
<string name="volume_stream_vibrate" translatable="false">%s vibrate</string>
|
||||
<string name="volume_stream_suppressed" translatable="false">%1$s silent — %2$s</string>
|
||||
<string name="volume_stream_muted_dnd" translatable="false">%s silent — No interruptions</string>
|
||||
<string name="volume_stream_limited_dnd" translatable="false">%s — Priority only</string>
|
||||
<string name="volume_stream_vibrate_dnd" translatable="false">%s vibrate — Priority only</string>
|
||||
<string name="volume_dnd_ends_in" translatable="false">Do not disturb ends in %s</string>
|
||||
<string name="volume_dnd_ends_at" translatable="false">Do not disturb ends at %s</string>
|
||||
<string name="volume_end_now" translatable="false">End now</string>
|
||||
|
||||
</resources>
|
||||
@@ -40,6 +40,7 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
|
||||
private static final String ACTION_SET_VISIBLE = "com.android.systemui.dndtile.SET_VISIBLE";
|
||||
private static final String EXTRA_VISIBLE = "visible";
|
||||
private static final String PREF_KEY_VISIBLE = "DndTileVisible";
|
||||
private static final String PREF_KEY_COMBINED_ICON = "DndTileCombinedIcon";
|
||||
|
||||
private final ZenModeController mController;
|
||||
private final DndDetailAdapter mDetailAdapter;
|
||||
@@ -52,7 +53,7 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
|
||||
super(host);
|
||||
mController = host.getZenModeController();
|
||||
mDetailAdapter = new DndDetailAdapter();
|
||||
mVisible = getSharedPrefs(mContext).getBoolean(PREF_KEY_VISIBLE, false);
|
||||
mVisible = isVisible(host.getContext());
|
||||
mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_SET_VISIBLE));
|
||||
}
|
||||
|
||||
@@ -65,6 +66,14 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
|
||||
return getSharedPrefs(context).getBoolean(PREF_KEY_VISIBLE, false);
|
||||
}
|
||||
|
||||
public static void setCombinedIcon(Context context, boolean combined) {
|
||||
getSharedPrefs(context).edit().putBoolean(PREF_KEY_COMBINED_ICON, combined).commit();
|
||||
}
|
||||
|
||||
public static boolean isCombinedIcon(Context context) {
|
||||
return getSharedPrefs(context).getBoolean(PREF_KEY_COMBINED_ICON, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DetailAdapter getDetailAdapter() {
|
||||
return mDetailAdapter;
|
||||
|
||||
@@ -199,7 +199,7 @@ public class PhoneStatusBarPolicy {
|
||||
int volumeIconId = 0;
|
||||
String volumeDescription = null;
|
||||
|
||||
if (DndTile.isVisible(mContext)) {
|
||||
if (DndTile.isVisible(mContext) || DndTile.isCombinedIcon(mContext)) {
|
||||
zenVisible = mZen != Global.ZEN_MODE_OFF;
|
||||
zenIconId = R.drawable.stat_sys_dnd;
|
||||
zenDescription = mContext.getString(R.string.quick_settings_dnd_label);
|
||||
|
||||
23
packages/SystemUI/src/com/android/systemui/volume/D.java
Normal file
23
packages/SystemUI/src/com/android/systemui/volume/D.java
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.volume;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
class D {
|
||||
public static boolean BUG = Log.isLoggable("volume", Log.DEBUG);
|
||||
}
|
||||
189
packages/SystemUI/src/com/android/systemui/volume/Events.java
Normal file
189
packages/SystemUI/src/com/android/systemui/volume/Events.java
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.volume;
|
||||
|
||||
import android.media.AudioManager;
|
||||
import android.media.AudioSystem;
|
||||
import android.provider.Settings.Global;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.systemui.volume.VolumeDialogController.State;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Interesting events related to the volume.
|
||||
*/
|
||||
public class Events {
|
||||
private static final String TAG = Util.logTag(Events.class);
|
||||
|
||||
public static final int EVENT_SHOW_DIALOG = 0; // (reason|int) (keyguard|bool)
|
||||
public static final int EVENT_DISMISS_DIALOG = 1; // (reason|int)
|
||||
public static final int EVENT_ACTIVE_STREAM_CHANGED = 2; // (stream|int)
|
||||
public static final int EVENT_EXPAND = 3; // (expand|bool)
|
||||
public static final int EVENT_KEY = 4;
|
||||
public static final int EVENT_COLLECTION_STARTED = 5;
|
||||
public static final int EVENT_COLLECTION_STOPPED = 6;
|
||||
public static final int EVENT_ICON_CLICK = 7; // (stream|int) (icon_state|int)
|
||||
public static final int EVENT_SETTINGS_CLICK = 8;
|
||||
public static final int EVENT_TOUCH_LEVEL_CHANGED = 9; // (stream|int) (level|int)
|
||||
public static final int EVENT_LEVEL_CHANGED = 10; // (stream|int) (level|int)
|
||||
public static final int EVENT_INTERNAL_RINGER_MODE_CHANGED = 11; // (mode|int)
|
||||
public static final int EVENT_EXTERNAL_RINGER_MODE_CHANGED = 12; // (mode|int)
|
||||
public static final int EVENT_ZEN_MODE_CHANGED = 13; // (mode|int)
|
||||
public static final int EVENT_SUPPRESSOR_CHANGED = 14; // (component|string) (name|string)
|
||||
public static final int EVENT_MUTE_CHANGED = 15; // (stream|int) (muted|bool)
|
||||
|
||||
private static final String[] EVENT_TAGS = {
|
||||
"show_dialog",
|
||||
"dismiss_dialog",
|
||||
"active_stream_changed",
|
||||
"expand",
|
||||
"key",
|
||||
"collection_started",
|
||||
"collection_stopped",
|
||||
"icon_click",
|
||||
"settings_click",
|
||||
"touch_level_changed",
|
||||
"level_changed",
|
||||
"internal_ringer_mode_changed",
|
||||
"external_ringer_mode_changed",
|
||||
"zen_mode_changed",
|
||||
"suppressor_changed",
|
||||
"mute_changed",
|
||||
};
|
||||
|
||||
public static final int DISMISS_REASON_UNKNOWN = 0;
|
||||
public static final int DISMISS_REASON_TOUCH_OUTSIDE = 1;
|
||||
public static final int DISMISS_REASON_VOLUME_CONTROLLER = 2;
|
||||
public static final int DISMISS_REASON_TIMEOUT = 3;
|
||||
public static final int DISMISS_REASON_SCREEN_OFF = 4;
|
||||
public static final int DISMISS_REASON_SETTINGS_CLICKED = 5;
|
||||
public static final int DISMISS_REASON_DONE_CLICKED = 6;
|
||||
public static final String[] DISMISS_REASONS = {
|
||||
"unknown",
|
||||
"touch_outside",
|
||||
"volume_controller",
|
||||
"timeout",
|
||||
"screen_off",
|
||||
"settings_clicked",
|
||||
"done_clicked",
|
||||
};
|
||||
|
||||
public static final int SHOW_REASON_UNKNOWN = 0;
|
||||
public static final int SHOW_REASON_VOLUME_CHANGED = 1;
|
||||
public static final int SHOW_REASON_REMOTE_VOLUME_CHANGED = 2;
|
||||
public static final String[] SHOW_REASONS = {
|
||||
"unknown",
|
||||
"volume_changed",
|
||||
"remote_volume_changed"
|
||||
};
|
||||
|
||||
public static final int ICON_STATE_UNKNOWN = 0;
|
||||
public static final int ICON_STATE_UNMUTE = 1;
|
||||
public static final int ICON_STATE_MUTE = 2;
|
||||
public static final int ICON_STATE_VIBRATE = 3;
|
||||
|
||||
public static Callback sCallback;
|
||||
|
||||
public static void writeEvent(int tag, Object... list) {
|
||||
final long time = System.currentTimeMillis();
|
||||
final StringBuilder sb = new StringBuilder("writeEvent ").append(EVENT_TAGS[tag]);
|
||||
if (list != null && list.length > 0) {
|
||||
sb.append(" ");
|
||||
switch (tag) {
|
||||
case EVENT_SHOW_DIALOG:
|
||||
sb.append(SHOW_REASONS[(Integer) list[0]]).append(" keyguard=").append(list[1]);
|
||||
break;
|
||||
case EVENT_EXPAND:
|
||||
sb.append(list[0]);
|
||||
break;
|
||||
case EVENT_DISMISS_DIALOG:
|
||||
sb.append(DISMISS_REASONS[(Integer) list[0]]);
|
||||
break;
|
||||
case EVENT_ACTIVE_STREAM_CHANGED:
|
||||
sb.append(AudioSystem.streamToString((Integer) list[0]));
|
||||
break;
|
||||
case EVENT_ICON_CLICK:
|
||||
sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ')
|
||||
.append(iconStateToString((Integer) list[1]));
|
||||
break;
|
||||
case EVENT_TOUCH_LEVEL_CHANGED:
|
||||
case EVENT_LEVEL_CHANGED:
|
||||
case EVENT_MUTE_CHANGED:
|
||||
sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ')
|
||||
.append(list[1]);
|
||||
break;
|
||||
case EVENT_INTERNAL_RINGER_MODE_CHANGED:
|
||||
case EVENT_EXTERNAL_RINGER_MODE_CHANGED:
|
||||
sb.append(ringerModeToString((Integer) list[0]));
|
||||
break;
|
||||
case EVENT_ZEN_MODE_CHANGED:
|
||||
sb.append(zenModeToString((Integer) list[0]));
|
||||
break;
|
||||
case EVENT_SUPPRESSOR_CHANGED:
|
||||
sb.append(list[0]).append(' ').append(list[1]);
|
||||
break;
|
||||
default:
|
||||
sb.append(Arrays.asList(list));
|
||||
break;
|
||||
}
|
||||
}
|
||||
Log.i(TAG, sb.toString());
|
||||
if (sCallback != null) {
|
||||
sCallback.writeEvent(time, tag, list);
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeState(long time, State state) {
|
||||
if (sCallback != null) {
|
||||
sCallback.writeState(time, state);
|
||||
}
|
||||
}
|
||||
|
||||
private static String iconStateToString(int iconState) {
|
||||
switch (iconState) {
|
||||
case ICON_STATE_UNMUTE: return "unmute";
|
||||
case ICON_STATE_MUTE: return "mute";
|
||||
case ICON_STATE_VIBRATE: return "vibrate";
|
||||
default: return "unknown_state_" + iconState;
|
||||
}
|
||||
}
|
||||
|
||||
private static String ringerModeToString(int ringerMode) {
|
||||
switch (ringerMode) {
|
||||
case AudioManager.RINGER_MODE_SILENT: return "silent";
|
||||
case AudioManager.RINGER_MODE_VIBRATE: return "vibrate";
|
||||
case AudioManager.RINGER_MODE_NORMAL: return "normal";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
private static String zenModeToString(int zenMode) {
|
||||
switch (zenMode) {
|
||||
case Global.ZEN_MODE_OFF: return "off";
|
||||
case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return "important_interruptions";
|
||||
case Global.ZEN_MODE_NO_INTERRUPTIONS: return "no_interruptions";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
void writeEvent(long time, int tag, Object[] list);
|
||||
void writeState(long time, State state);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.volume;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.media.IRemoteVolumeController;
|
||||
import android.media.MediaMetadata;
|
||||
import android.media.session.ISessionController;
|
||||
import android.media.session.MediaController;
|
||||
import android.media.session.MediaController.PlaybackInfo;
|
||||
import android.media.session.MediaSession.QueueItem;
|
||||
import android.media.session.MediaSession.Token;
|
||||
import android.media.session.MediaSessionManager;
|
||||
import android.media.session.MediaSessionManager.OnActiveSessionsChangedListener;
|
||||
import android.media.session.PlaybackState;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Convenience client for all media session updates. Provides a callback interface for events
|
||||
* related to remote media sessions.
|
||||
*/
|
||||
public class MediaSessions {
|
||||
private static final String TAG = Util.logTag(MediaSessions.class);
|
||||
|
||||
private static final boolean USE_SERVICE_LABEL = false;
|
||||
|
||||
private final Context mContext;
|
||||
private final H mHandler;
|
||||
private final MediaSessionManager mMgr;
|
||||
private final Map<Token, MediaControllerRecord> mRecords = new HashMap<>();
|
||||
private final Callbacks mCallbacks;
|
||||
|
||||
private boolean mInit;
|
||||
|
||||
public MediaSessions(Context context, Looper looper, Callbacks callbacks) {
|
||||
mContext = context;
|
||||
mHandler = new H(looper);
|
||||
mMgr = (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
|
||||
mCallbacks = callbacks;
|
||||
}
|
||||
|
||||
public void dump(PrintWriter writer) {
|
||||
writer.println(getClass().getSimpleName() + " state:");
|
||||
writer.print(" mInit: "); writer.println(mInit);
|
||||
writer.print(" mRecords.size: "); writer.println(mRecords.size());
|
||||
int i = 0;
|
||||
for (MediaControllerRecord r : mRecords.values()) {
|
||||
dump(++i, writer, r.controller);
|
||||
}
|
||||
}
|
||||
|
||||
public void init() {
|
||||
if (D.BUG) Log.d(TAG, "init");
|
||||
// will throw if no permission
|
||||
mMgr.addOnActiveSessionsChangedListener(mSessionsListener, null, mHandler);
|
||||
mInit = true;
|
||||
postUpdateSessions();
|
||||
mMgr.setRemoteVolumeController(mRvc);
|
||||
}
|
||||
|
||||
protected void postUpdateSessions() {
|
||||
if (!mInit) return;
|
||||
mHandler.sendEmptyMessage(H.UPDATE_SESSIONS);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (D.BUG) Log.d(TAG, "destroy");
|
||||
mInit = false;
|
||||
mMgr.removeOnActiveSessionsChangedListener(mSessionsListener);
|
||||
}
|
||||
|
||||
public void setVolume(Token token, int level) {
|
||||
final MediaControllerRecord r = mRecords.get(token);
|
||||
if (r == null) {
|
||||
Log.w(TAG, "setVolume: No record found for token " + token);
|
||||
return;
|
||||
}
|
||||
if (D.BUG) Log.d(TAG, "Setting level to " + level);
|
||||
r.controller.setVolumeTo(level, 0);
|
||||
}
|
||||
|
||||
private void onRemoteVolumeChangedH(ISessionController session, int flags) {
|
||||
final MediaController controller = new MediaController(mContext, session);
|
||||
if (D.BUG) Log.d(TAG, "remoteVolumeChangedH " + controller.getPackageName() + " "
|
||||
+ Util.audioManagerFlagsToString(flags));
|
||||
final Token token = controller.getSessionToken();
|
||||
mCallbacks.onRemoteVolumeChanged(token, flags);
|
||||
}
|
||||
|
||||
private void onUpdateRemoteControllerH(ISessionController session) {
|
||||
final MediaController controller = session != null ? new MediaController(mContext, session)
|
||||
: null;
|
||||
final String pkg = controller != null ? controller.getPackageName() : null;
|
||||
if (D.BUG) Log.d(TAG, "updateRemoteControllerH " + pkg);
|
||||
// this may be our only indication that a remote session is changed, refresh
|
||||
postUpdateSessions();
|
||||
}
|
||||
|
||||
protected void onActiveSessionsUpdatedH(List<MediaController> controllers) {
|
||||
if (D.BUG) Log.d(TAG, "onActiveSessionsUpdatedH n=" + controllers.size());
|
||||
final Set<Token> toRemove = new HashSet<Token>(mRecords.keySet());
|
||||
for (MediaController controller : controllers) {
|
||||
final Token token = controller.getSessionToken();
|
||||
final PlaybackInfo pi = controller.getPlaybackInfo();
|
||||
toRemove.remove(token);
|
||||
if (!mRecords.containsKey(token)) {
|
||||
final MediaControllerRecord r = new MediaControllerRecord(controller);
|
||||
r.name = getControllerName(controller);
|
||||
mRecords.put(token, r);
|
||||
controller.registerCallback(r, mHandler);
|
||||
}
|
||||
final MediaControllerRecord r = mRecords.get(token);
|
||||
final boolean remote = isRemote(pi);
|
||||
if (remote) {
|
||||
updateRemoteH(token, r.name, pi);
|
||||
r.sentRemote = true;
|
||||
}
|
||||
}
|
||||
for (Token t : toRemove) {
|
||||
final MediaControllerRecord r = mRecords.get(t);
|
||||
r.controller.unregisterCallback(r);
|
||||
mRecords.remove(t);
|
||||
if (D.BUG) Log.d(TAG, "Removing " + r.name + " sentRemote=" + r.sentRemote);
|
||||
if (r.sentRemote) {
|
||||
mCallbacks.onRemoteRemoved(t);
|
||||
r.sentRemote = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isRemote(PlaybackInfo pi) {
|
||||
return pi != null && pi.getPlaybackType() == PlaybackInfo.PLAYBACK_TYPE_REMOTE;
|
||||
}
|
||||
|
||||
protected String getControllerName(MediaController controller) {
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
final String pkg = controller.getPackageName();
|
||||
try {
|
||||
if (USE_SERVICE_LABEL) {
|
||||
final List<ResolveInfo> ris = pm.queryIntentServices(
|
||||
new Intent("android.media.MediaRouteProviderService").setPackage(pkg), 0);
|
||||
if (ris != null) {
|
||||
for (ResolveInfo ri : ris) {
|
||||
if (ri.serviceInfo == null) continue;
|
||||
if (pkg.equals(ri.serviceInfo.packageName)) {
|
||||
final String serviceLabel =
|
||||
Objects.toString(ri.serviceInfo.loadLabel(pm), "").trim();
|
||||
if (serviceLabel.length() > 0) {
|
||||
return serviceLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
final ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
|
||||
final String appLabel = Objects.toString(ai.loadLabel(pm), "").trim();
|
||||
if (appLabel.length() > 0) {
|
||||
return appLabel;
|
||||
}
|
||||
} catch (NameNotFoundException e) { }
|
||||
return pkg;
|
||||
}
|
||||
|
||||
private void updateRemoteH(Token token, String name, PlaybackInfo pi) {
|
||||
if (mCallbacks != null) {
|
||||
mCallbacks.onRemoteUpdate(token, name, pi);
|
||||
}
|
||||
}
|
||||
|
||||
private static void dump(int n, PrintWriter writer, MediaController c) {
|
||||
writer.println(" Controller " + n + ": " + c.getPackageName());
|
||||
final Bundle extras = c.getExtras();
|
||||
final long flags = c.getFlags();
|
||||
final MediaMetadata mm = c.getMetadata();
|
||||
final PlaybackInfo pi = c.getPlaybackInfo();
|
||||
final PlaybackState playbackState = c.getPlaybackState();
|
||||
final List<QueueItem> queue = c.getQueue();
|
||||
final CharSequence queueTitle = c.getQueueTitle();
|
||||
final int ratingType = c.getRatingType();
|
||||
final PendingIntent sessionActivity = c.getSessionActivity();
|
||||
|
||||
writer.println(" PlaybackState: " + Util.playbackStateToString(playbackState));
|
||||
writer.println(" PlaybackInfo: " + Util.playbackInfoToString(pi));
|
||||
if (mm != null) {
|
||||
writer.println(" MediaMetadata.desc=" + mm.getDescription());
|
||||
}
|
||||
writer.println(" RatingType: " + ratingType);
|
||||
writer.println(" Flags: " + flags);
|
||||
if (extras != null) {
|
||||
writer.println(" Extras:");
|
||||
for (String key : extras.keySet()) {
|
||||
writer.println(" " + key + "=" + extras.get(key));
|
||||
}
|
||||
}
|
||||
if (queueTitle != null) {
|
||||
writer.println(" QueueTitle: " + queueTitle);
|
||||
}
|
||||
if (queue != null && !queue.isEmpty()) {
|
||||
writer.println(" Queue:");
|
||||
for (QueueItem qi : queue) {
|
||||
writer.println(" " + qi);
|
||||
}
|
||||
}
|
||||
if (pi != null) {
|
||||
writer.println(" sessionActivity: " + sessionActivity);
|
||||
}
|
||||
}
|
||||
|
||||
public static void dumpMediaSessions(Context context) {
|
||||
final MediaSessionManager mgr = (MediaSessionManager) context
|
||||
.getSystemService(Context.MEDIA_SESSION_SERVICE);
|
||||
try {
|
||||
final List<MediaController> controllers = mgr.getActiveSessions(null);
|
||||
final int N = controllers.size();
|
||||
if (D.BUG) Log.d(TAG, N + " controllers");
|
||||
for (int i = 0; i < N; i++) {
|
||||
final StringWriter sw = new StringWriter();
|
||||
final PrintWriter pw = new PrintWriter(sw, true);
|
||||
dump(i + 1, pw, controllers.get(i));
|
||||
if (D.BUG) Log.d(TAG, sw.toString());
|
||||
}
|
||||
} catch (SecurityException e) {
|
||||
Log.w(TAG, "Not allowed to get sessions", e);
|
||||
}
|
||||
}
|
||||
|
||||
private final class MediaControllerRecord extends MediaController.Callback {
|
||||
private final MediaController controller;
|
||||
|
||||
private boolean sentRemote;
|
||||
private String name;
|
||||
|
||||
private MediaControllerRecord(MediaController controller) {
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
private String cb(String method) {
|
||||
return method + " " + controller.getPackageName() + " ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAudioInfoChanged(PlaybackInfo info) {
|
||||
if (D.BUG) Log.d(TAG, cb("onAudioInfoChanged") + Util.playbackInfoToString(info)
|
||||
+ " sentRemote=" + sentRemote);
|
||||
final boolean remote = isRemote(info);
|
||||
if (!remote && sentRemote) {
|
||||
mCallbacks.onRemoteRemoved(controller.getSessionToken());
|
||||
sentRemote = false;
|
||||
} else if (remote) {
|
||||
updateRemoteH(controller.getSessionToken(), name, info);
|
||||
sentRemote = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExtrasChanged(Bundle extras) {
|
||||
if (D.BUG) Log.d(TAG, cb("onExtrasChanged") + extras);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMetadataChanged(MediaMetadata metadata) {
|
||||
if (D.BUG) Log.d(TAG, cb("onMetadataChanged") + Util.mediaMetadataToString(metadata));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaybackStateChanged(PlaybackState state) {
|
||||
if (D.BUG) Log.d(TAG, cb("onPlaybackStateChanged") + Util.playbackStateToString(state));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueueChanged(List<QueueItem> queue) {
|
||||
if (D.BUG) Log.d(TAG, cb("onQueueChanged") + queue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueueTitleChanged(CharSequence title) {
|
||||
if (D.BUG) Log.d(TAG, cb("onQueueTitleChanged") + title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionDestroyed() {
|
||||
if (D.BUG) Log.d(TAG, cb("onSessionDestroyed"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionEvent(String event, Bundle extras) {
|
||||
if (D.BUG) Log.d(TAG, cb("onSessionEvent") + "event=" + event + " extras=" + extras);
|
||||
}
|
||||
}
|
||||
|
||||
private final OnActiveSessionsChangedListener mSessionsListener =
|
||||
new OnActiveSessionsChangedListener() {
|
||||
@Override
|
||||
public void onActiveSessionsChanged(List<MediaController> controllers) {
|
||||
onActiveSessionsUpdatedH(controllers);
|
||||
}
|
||||
};
|
||||
|
||||
private final IRemoteVolumeController mRvc = new IRemoteVolumeController.Stub() {
|
||||
@Override
|
||||
public void remoteVolumeChanged(ISessionController session, int flags)
|
||||
throws RemoteException {
|
||||
mHandler.obtainMessage(H.REMOTE_VOLUME_CHANGED, flags, 0, session).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRemoteController(final ISessionController session)
|
||||
throws RemoteException {
|
||||
mHandler.obtainMessage(H.UPDATE_REMOTE_CONTROLLER, session).sendToTarget();
|
||||
}
|
||||
};
|
||||
|
||||
private final class H extends Handler {
|
||||
private static final int UPDATE_SESSIONS = 1;
|
||||
private static final int REMOTE_VOLUME_CHANGED = 2;
|
||||
private static final int UPDATE_REMOTE_CONTROLLER = 3;
|
||||
|
||||
private H(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case UPDATE_SESSIONS:
|
||||
onActiveSessionsUpdatedH(mMgr.getActiveSessions(null));
|
||||
break;
|
||||
case REMOTE_VOLUME_CHANGED:
|
||||
onRemoteVolumeChangedH((ISessionController) msg.obj, msg.arg1);
|
||||
break;
|
||||
case UPDATE_REMOTE_CONTROLLER:
|
||||
onUpdateRemoteControllerH((ISessionController) msg.obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface Callbacks {
|
||||
void onRemoteUpdate(Token token, String name, PlaybackInfo pi);
|
||||
void onRemoteRemoved(Token t);
|
||||
void onRemoteVolumeChanged(Token token, int flags);
|
||||
}
|
||||
|
||||
}
|
||||
69
packages/SystemUI/src/com/android/systemui/volume/Prefs.java
Normal file
69
packages/SystemUI/src/com/android/systemui/volume/Prefs.java
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.volume;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
/**
|
||||
* Configuration for the volume dialog + related policy.
|
||||
*/
|
||||
public class Prefs {
|
||||
|
||||
public static final String PREF_ENABLE_PROTOTYPE = "pref_enable_prototype"; // not persistent
|
||||
public static final String PREF_SHOW_ALARMS = "pref_show_alarms";
|
||||
public static final String PREF_SHOW_SYSTEM = "pref_show_system";
|
||||
public static final String PREF_SHOW_HEADERS = "pref_show_headers";
|
||||
public static final String PREF_SHOW_FAKE_REMOTE_1 = "pref_show_fake_remote_1";
|
||||
public static final String PREF_SHOW_FAKE_REMOTE_2 = "pref_show_fake_remote_2";
|
||||
public static final String PREF_SHOW_FOOTER = "pref_show_footer";
|
||||
public static final String PREF_ZEN_FOOTER = "pref_zen_footer";
|
||||
public static final String PREF_ENABLE_AUTOMUTE = "pref_enable_automute";
|
||||
public static final String PREF_ENABLE_SILENT_MODE = "pref_enable_silent_mode";
|
||||
public static final String PREF_DEBUG_LOGGING = "pref_debug_logging";
|
||||
public static final String PREF_SEND_LOGS = "pref_send_logs";
|
||||
public static final String PREF_ADJUST_SYSTEM = "pref_adjust_system";
|
||||
public static final String PREF_ADJUST_VOICE_CALLS = "pref_adjust_voice_calls";
|
||||
public static final String PREF_ADJUST_BLUETOOTH_SCO = "pref_adjust_bluetooth_sco";
|
||||
public static final String PREF_ADJUST_MEDIA = "pref_adjust_media";
|
||||
public static final String PREF_ADJUST_ALARMS = "pref_adjust_alarms";
|
||||
public static final String PREF_ADJUST_NOTIFICATION = "pref_adjust_notification";
|
||||
|
||||
public static final boolean DEFAULT_SHOW_HEADERS = true;
|
||||
public static final boolean DEFAULT_SHOW_FOOTER = true;
|
||||
public static final boolean DEFAULT_ENABLE_AUTOMUTE = true;
|
||||
public static final boolean DEFAULT_ENABLE_SILENT_MODE = true;
|
||||
public static final boolean DEFAULT_ZEN_FOOTER = true;
|
||||
|
||||
public static void unregisterCallbacks(Context c, OnSharedPreferenceChangeListener listener) {
|
||||
prefs(c).unregisterOnSharedPreferenceChangeListener(listener);
|
||||
}
|
||||
|
||||
public static void registerCallbacks(Context c, OnSharedPreferenceChangeListener listener) {
|
||||
prefs(c).registerOnSharedPreferenceChangeListener(listener);
|
||||
}
|
||||
|
||||
private static SharedPreferences prefs(Context context) {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context);
|
||||
}
|
||||
|
||||
public static boolean get(Context context, String key, boolean def) {
|
||||
return prefs(context).getBoolean(key, def);
|
||||
}
|
||||
}
|
||||
@@ -60,17 +60,14 @@ public class SegmentedButtons extends LinearLayout {
|
||||
final Object tag = c.getTag();
|
||||
final boolean selected = Objects.equals(mSelectedValue, tag);
|
||||
c.setSelected(selected);
|
||||
c.getCompoundDrawables()[1].setTint(mContext.getColor(selected
|
||||
? R.color.segmented_button_selected : R.color.segmented_button_unselected));
|
||||
}
|
||||
fireOnSelected();
|
||||
}
|
||||
|
||||
public void addButton(int labelResId, int iconResId, Object value) {
|
||||
public void addButton(int labelResId, Object value) {
|
||||
final Button b = (Button) mInflater.inflate(R.layout.segmented_button, this, false);
|
||||
b.setTag(LABEL_RES_KEY, labelResId);
|
||||
b.setText(labelResId);
|
||||
b.setCompoundDrawablesWithIntrinsicBounds(0, iconResId, 0, 0);
|
||||
final LayoutParams lp = (LayoutParams) b.getLayoutParams();
|
||||
if (getChildCount() == 0) {
|
||||
lp.leftMargin = lp.rightMargin = 0; // first button has no margin
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.volume;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.view.View.OnAttachStateChangeListener;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* Capture initial sp values for registered textviews, and update properly when configuration
|
||||
* changes.
|
||||
*/
|
||||
public class SpTexts {
|
||||
|
||||
private final Context mContext;
|
||||
private final ArrayMap<TextView, Integer> mTexts = new ArrayMap<>();
|
||||
|
||||
public SpTexts(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public int add(final TextView text) {
|
||||
if (text == null) return 0;
|
||||
final Resources res = mContext.getResources();
|
||||
final float fontScale = res.getConfiguration().fontScale;
|
||||
final float density = res.getDisplayMetrics().density;
|
||||
final float px = text.getTextSize();
|
||||
final int sp = (int)(px / fontScale / density);
|
||||
mTexts.put(text, sp);
|
||||
text.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
setTextSizeH(text, sp);
|
||||
}
|
||||
});
|
||||
return sp;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (mTexts.isEmpty()) return;
|
||||
mTexts.keyAt(0).post(mUpdateAll);
|
||||
}
|
||||
|
||||
private void setTextSizeH(TextView text, int sp) {
|
||||
text.setTextSize(TypedValue.COMPLEX_UNIT_SP, sp);
|
||||
}
|
||||
|
||||
private final Runnable mUpdateAll = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < mTexts.size(); i++) {
|
||||
setTextSizeH(mTexts.keyAt(i), mTexts.valueAt(i));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
165
packages/SystemUI/src/com/android/systemui/volume/Util.java
Normal file
165
packages/SystemUI/src/com/android/systemui/volume/Util.java
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.volume;
|
||||
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaMetadata;
|
||||
import android.media.VolumeProvider;
|
||||
import android.media.session.MediaController.PlaybackInfo;
|
||||
import android.media.session.PlaybackState;
|
||||
import android.service.notification.ZenModeConfig.DowntimeInfo;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Static helpers for the volume dialog.
|
||||
*/
|
||||
class Util {
|
||||
|
||||
// Note: currently not shown (only used in the text footer)
|
||||
private static final SimpleDateFormat HMMAA = new SimpleDateFormat("h:mm aa", Locale.US);
|
||||
|
||||
private static int[] AUDIO_MANAGER_FLAGS = new int[] {
|
||||
AudioManager.FLAG_SHOW_UI,
|
||||
AudioManager.FLAG_VIBRATE,
|
||||
AudioManager.FLAG_PLAY_SOUND,
|
||||
AudioManager.FLAG_ALLOW_RINGER_MODES,
|
||||
AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE,
|
||||
AudioManager.FLAG_SHOW_VIBRATE_HINT,
|
||||
AudioManager.FLAG_SHOW_SILENT_HINT,
|
||||
AudioManager.FLAG_FROM_KEY,
|
||||
};
|
||||
|
||||
private static String[] AUDIO_MANAGER_FLAG_NAMES = new String[] {
|
||||
"SHOW_UI",
|
||||
"VIBRATE",
|
||||
"PLAY_SOUND",
|
||||
"ALLOW_RINGER_MODES",
|
||||
"REMOVE_SOUND_AND_VIBRATE",
|
||||
"SHOW_VIBRATE_HINT",
|
||||
"SHOW_SILENT_HINT",
|
||||
"FROM_KEY",
|
||||
};
|
||||
|
||||
public static String logTag(Class<?> c) {
|
||||
final String tag = "vol." + c.getSimpleName();
|
||||
return tag.length() < 23 ? tag : tag.substring(0, 23);
|
||||
}
|
||||
|
||||
public static String ringerModeToString(int ringerMode) {
|
||||
switch (ringerMode) {
|
||||
case AudioManager.RINGER_MODE_SILENT: return "RINGER_MODE_SILENT";
|
||||
case AudioManager.RINGER_MODE_VIBRATE: return "RINGER_MODE_VIBRATE";
|
||||
case AudioManager.RINGER_MODE_NORMAL: return "RINGER_MODE_NORMAL";
|
||||
default: return "RINGER_MODE_UNKNOWN_" + ringerMode;
|
||||
}
|
||||
}
|
||||
|
||||
public static String mediaMetadataToString(MediaMetadata metadata) {
|
||||
return metadata.getDescription().toString();
|
||||
}
|
||||
|
||||
public static String playbackInfoToString(PlaybackInfo info) {
|
||||
if (info == null) return null;
|
||||
final String type = playbackInfoTypeToString(info.getPlaybackType());
|
||||
final String vc = volumeProviderControlToString(info.getVolumeControl());
|
||||
return String.format("PlaybackInfo[vol=%s,max=%s,type=%s,vc=%s],atts=%s",
|
||||
info.getCurrentVolume(), info.getMaxVolume(), type, vc, info.getAudioAttributes());
|
||||
}
|
||||
|
||||
public static String playbackInfoTypeToString(int type) {
|
||||
switch (type) {
|
||||
case PlaybackInfo.PLAYBACK_TYPE_LOCAL: return "LOCAL";
|
||||
case PlaybackInfo.PLAYBACK_TYPE_REMOTE: return "REMOTE";
|
||||
default: return "UNKNOWN_" + type;
|
||||
}
|
||||
}
|
||||
|
||||
public static String playbackStateStateToString(int state) {
|
||||
switch (state) {
|
||||
case PlaybackState.STATE_NONE: return "STATE_NONE";
|
||||
case PlaybackState.STATE_STOPPED: return "STATE_STOPPED";
|
||||
case PlaybackState.STATE_PAUSED: return "STATE_PAUSED";
|
||||
case PlaybackState.STATE_PLAYING: return "STATE_PLAYING";
|
||||
default: return "UNKNOWN_" + state;
|
||||
}
|
||||
}
|
||||
|
||||
public static String volumeProviderControlToString(int control) {
|
||||
switch (control) {
|
||||
case VolumeProvider.VOLUME_CONTROL_ABSOLUTE: return "VOLUME_CONTROL_ABSOLUTE";
|
||||
case VolumeProvider.VOLUME_CONTROL_FIXED: return "VOLUME_CONTROL_FIXED";
|
||||
case VolumeProvider.VOLUME_CONTROL_RELATIVE: return "VOLUME_CONTROL_RELATIVE";
|
||||
default: return "VOLUME_CONTROL_UNKNOWN_" + control;
|
||||
}
|
||||
}
|
||||
|
||||
public static String playbackStateToString(PlaybackState playbackState) {
|
||||
if (playbackState == null) return null;
|
||||
return playbackStateStateToString(playbackState.getState()) + " " + playbackState;
|
||||
}
|
||||
|
||||
public static String audioManagerFlagsToString(int value) {
|
||||
return bitFieldToString(value, AUDIO_MANAGER_FLAGS, AUDIO_MANAGER_FLAG_NAMES);
|
||||
}
|
||||
|
||||
private static String bitFieldToString(int value, int[] values, String[] names) {
|
||||
if (value == 0) return "";
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if ((value & values[i]) != 0) {
|
||||
if (sb.length() > 0) sb.append(',');
|
||||
sb.append(names[i]);
|
||||
}
|
||||
value &= ~values[i];
|
||||
}
|
||||
if (value != 0) {
|
||||
if (sb.length() > 0) sb.append(',');
|
||||
sb.append("UNKNOWN_").append(value);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String getShortTime(long millis) {
|
||||
return HMMAA.format(new Date(millis));
|
||||
}
|
||||
|
||||
public static String getShortTime(DowntimeInfo info) {
|
||||
return ((info.endHour + 1) % 12) + ":" + (info.endMinute < 10 ? " " : "") + info.endMinute;
|
||||
}
|
||||
|
||||
public static void setText(TextView tv, CharSequence text) {
|
||||
if (Objects.equals(tv.getText(), text)) return;
|
||||
tv.setText(text);
|
||||
}
|
||||
|
||||
public static final void setVisOrGone(View v, boolean vis) {
|
||||
if (v == null || (v.getVisibility() == View.VISIBLE) == vis) return;
|
||||
v.setVisibility(vis ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
public static final void setVisOrInvis(View v, boolean vis) {
|
||||
if (v == null || (v.getVisibility() == View.VISIBLE) == vis) return;
|
||||
v.setVisibility(vis ? View.VISIBLE : View.INVISIBLE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,10 +16,18 @@
|
||||
|
||||
package com.android.systemui.volume;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
|
||||
import com.android.systemui.DemoMode;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
public interface VolumeComponent extends DemoMode {
|
||||
ZenModeController getZenController();
|
||||
void dismissNow();
|
||||
void onConfigurationChanged(Configuration newConfig);
|
||||
void dump(FileDescriptor fd, PrintWriter pw, String[] args);
|
||||
void register();
|
||||
}
|
||||
|
||||
1039
packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
Normal file
1039
packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.volume;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.media.AudioManager;
|
||||
import android.media.VolumePolicy;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
|
||||
import com.android.systemui.SystemUI;
|
||||
import com.android.systemui.keyguard.KeyguardViewMediator;
|
||||
import com.android.systemui.qs.tiles.DndTile;
|
||||
import com.android.systemui.statusbar.phone.PhoneStatusBar;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Implementation of VolumeComponent backed by the new volume dialog.
|
||||
*/
|
||||
public class VolumeDialogComponent implements VolumeComponent {
|
||||
private final SystemUI mSysui;
|
||||
private final Context mContext;
|
||||
private final VolumeDialogController mController;
|
||||
private final ZenModeController mZenModeController;
|
||||
private final VolumeDialog mDialog;
|
||||
|
||||
public VolumeDialogComponent(SystemUI sysui, Context context, Handler handler,
|
||||
ZenModeController zen) {
|
||||
mSysui = sysui;
|
||||
mContext = context;
|
||||
mController = new VolumeDialogController(context, null) {
|
||||
@Override
|
||||
protected void onUserActivityW() {
|
||||
sendUserActivity();
|
||||
}
|
||||
};
|
||||
mZenModeController = zen;
|
||||
mDialog = new VolumeDialog(context, mController, zen) {
|
||||
@Override
|
||||
protected void onZenSettingsClickedH() {
|
||||
startZenSettings();
|
||||
}
|
||||
};
|
||||
applyConfiguration();
|
||||
}
|
||||
|
||||
private void sendUserActivity() {
|
||||
final KeyguardViewMediator kvm = mSysui.getComponent(KeyguardViewMediator.class);
|
||||
if (kvm != null) {
|
||||
kvm.userActivity();
|
||||
}
|
||||
}
|
||||
|
||||
private void applyConfiguration() {
|
||||
mDialog.setStreamImportant(AudioManager.STREAM_ALARM, true);
|
||||
mDialog.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
|
||||
mDialog.setShowHeaders(false);
|
||||
mDialog.setShowFooter(true);
|
||||
mDialog.setZenFooter(true);
|
||||
mDialog.setAutomute(true);
|
||||
mDialog.setSilentMode(false);
|
||||
mController.setVolumePolicy(VolumePolicy.DEFAULT);
|
||||
mController.showDndTile(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZenModeController getZenController() {
|
||||
return mZenModeController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismissNow() {
|
||||
mController.dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchDemoCommand(String command, Bundle args) {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register() {
|
||||
mController.register();
|
||||
DndTile.setCombinedIcon(mContext, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
mController.dump(fd, pw, args);
|
||||
mDialog.dump(pw);
|
||||
}
|
||||
|
||||
private void startZenSettings() {
|
||||
mSysui.getComponent(PhoneStatusBar.class).startActivityDismissingKeyguard(
|
||||
ZenModePanel.ZEN_SETTINGS, true /* onlyProvisioned */, true /* dismissShade */);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,962 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.volume;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.database.ContentObserver;
|
||||
import android.media.AudioManager;
|
||||
import android.media.AudioSystem;
|
||||
import android.media.IVolumeController;
|
||||
import android.media.VolumePolicy;
|
||||
import android.media.session.MediaController.PlaybackInfo;
|
||||
import android.media.session.MediaSession.Token;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.os.Vibrator;
|
||||
import android.provider.Settings;
|
||||
import android.service.notification.Condition;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.systemui.R;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Source of truth for all state / events related to the volume dialog. No presentation.
|
||||
*
|
||||
* All work done on a dedicated background worker thread & associated worker.
|
||||
*
|
||||
* Methods ending in "W" must be called on the worker thread.
|
||||
*/
|
||||
public class VolumeDialogController {
|
||||
private static final String TAG = Util.logTag(VolumeDialogController.class);
|
||||
|
||||
private static final int DYNAMIC_STREAM_START_INDEX = 100;
|
||||
private static final int VIBRATE_HINT_DURATION = 50;
|
||||
|
||||
private static final int[] STREAMS = {
|
||||
AudioSystem.STREAM_ALARM,
|
||||
AudioSystem.STREAM_BLUETOOTH_SCO,
|
||||
AudioSystem.STREAM_DTMF,
|
||||
AudioSystem.STREAM_MUSIC,
|
||||
AudioSystem.STREAM_NOTIFICATION,
|
||||
AudioSystem.STREAM_RING,
|
||||
AudioSystem.STREAM_SYSTEM,
|
||||
AudioSystem.STREAM_SYSTEM_ENFORCED,
|
||||
AudioSystem.STREAM_TTS,
|
||||
AudioSystem.STREAM_VOICE_CALL,
|
||||
};
|
||||
|
||||
private final HandlerThread mWorkerThread;
|
||||
private final W mWorker;
|
||||
private final Context mContext;
|
||||
private final AudioManager mAudio;
|
||||
private final NotificationManager mNoMan;
|
||||
private final ComponentName mComponent;
|
||||
private final SettingObserver mObserver;
|
||||
private final Receiver mReceiver = new Receiver();
|
||||
private final MediaSessions mMediaSessions;
|
||||
private final VC mVolumeController = new VC();
|
||||
private final C mCallbacks = new C();
|
||||
private final State mState = new State();
|
||||
private final String[] mStreamTitles;
|
||||
private final MediaSessionsCallbacks mMediaSessionsCallbacksW = new MediaSessionsCallbacks();
|
||||
private final Vibrator mVibrator;
|
||||
private final boolean mHasVibrator;
|
||||
|
||||
private boolean mEnabled;
|
||||
private boolean mDestroyed;
|
||||
private VolumePolicy mVolumePolicy = new VolumePolicy(true, true, false, 400);
|
||||
private boolean mShowDndTile = false;
|
||||
|
||||
public VolumeDialogController(Context context, ComponentName component) {
|
||||
mContext = context.getApplicationContext();
|
||||
Events.writeEvent(Events.EVENT_COLLECTION_STARTED);
|
||||
mComponent = component;
|
||||
mWorkerThread = new HandlerThread(VolumeDialogController.class.getSimpleName());
|
||||
mWorkerThread.start();
|
||||
mWorker = new W(mWorkerThread.getLooper());
|
||||
mMediaSessions = createMediaSessions(mContext, mWorkerThread.getLooper(),
|
||||
mMediaSessionsCallbacksW);
|
||||
mAudio = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
mNoMan = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
mObserver = new SettingObserver(mWorker);
|
||||
mObserver.init();
|
||||
mReceiver.init();
|
||||
mStreamTitles = mContext.getResources().getStringArray(R.array.volume_stream_titles);
|
||||
mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
mHasVibrator = mVibrator != null && mVibrator.hasVibrator();
|
||||
}
|
||||
|
||||
public void dismiss() {
|
||||
mCallbacks.onDismissRequested(Events.DISMISS_REASON_VOLUME_CONTROLLER);
|
||||
}
|
||||
|
||||
public void register() {
|
||||
try {
|
||||
mAudio.setVolumeController(mVolumeController);
|
||||
} catch (SecurityException e) {
|
||||
Log.w(TAG, "Unable to set the volume controller", e);
|
||||
return;
|
||||
}
|
||||
setVolumePolicy(mVolumePolicy);
|
||||
showDndTile(mShowDndTile);
|
||||
try {
|
||||
mMediaSessions.init();
|
||||
} catch (SecurityException e) {
|
||||
Log.w(TAG, "No access to media sessions", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setVolumePolicy(VolumePolicy policy) {
|
||||
mVolumePolicy = policy;
|
||||
try {
|
||||
mAudio.setVolumePolicy(mVolumePolicy);
|
||||
} catch (NoSuchMethodError e) {
|
||||
Log.w(TAG, "No volume policy api");
|
||||
}
|
||||
}
|
||||
|
||||
protected MediaSessions createMediaSessions(Context context, Looper looper,
|
||||
MediaSessions.Callbacks callbacks) {
|
||||
return new MediaSessions(context, looper, callbacks);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (D.BUG) Log.d(TAG, "destroy");
|
||||
if (mDestroyed) return;
|
||||
mDestroyed = true;
|
||||
Events.writeEvent(Events.EVENT_COLLECTION_STOPPED);
|
||||
mMediaSessions.destroy();
|
||||
mObserver.destroy();
|
||||
mReceiver.destroy();
|
||||
mWorkerThread.quitSafely();
|
||||
}
|
||||
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.println(VolumeDialogController.class.getSimpleName() + " state:");
|
||||
pw.print(" mEnabled: "); pw.println(mEnabled);
|
||||
pw.print(" mDestroyed: "); pw.println(mDestroyed);
|
||||
pw.print(" mVolumePolicy: "); pw.println(mVolumePolicy);
|
||||
pw.print(" mEnabled: "); pw.println(mEnabled);
|
||||
pw.print(" mShowDndTile: "); pw.println(mShowDndTile);
|
||||
pw.print(" mHasVibrator: "); pw.println(mHasVibrator);
|
||||
pw.print(" mRemoteStreams: "); pw.println(mMediaSessionsCallbacksW.mRemoteStreams
|
||||
.values());
|
||||
pw.println();
|
||||
mMediaSessions.dump(pw);
|
||||
}
|
||||
|
||||
public void addCallback(Callbacks callback, Handler handler) {
|
||||
mCallbacks.add(callback, handler);
|
||||
}
|
||||
|
||||
public void removeCallback(Callbacks callback) {
|
||||
mCallbacks.remove(callback);
|
||||
}
|
||||
|
||||
public void getState() {
|
||||
if (mDestroyed) return;
|
||||
mWorker.sendEmptyMessage(W.GET_STATE);
|
||||
}
|
||||
|
||||
public void notifyVisible(boolean visible) {
|
||||
if (mDestroyed) return;
|
||||
mWorker.obtainMessage(W.NOTIFY_VISIBLE, visible ? 1 : 0, 0).sendToTarget();
|
||||
}
|
||||
|
||||
public void userActivity() {
|
||||
if (mDestroyed) return;
|
||||
mWorker.removeMessages(W.USER_ACTIVITY);
|
||||
mWorker.sendEmptyMessage(W.USER_ACTIVITY);
|
||||
}
|
||||
|
||||
public void setRingerMode(int value, boolean external) {
|
||||
if (mDestroyed) return;
|
||||
mWorker.obtainMessage(W.SET_RINGER_MODE, value, external ? 1 : 0).sendToTarget();
|
||||
}
|
||||
|
||||
public void setZenMode(int value) {
|
||||
if (mDestroyed) return;
|
||||
mWorker.obtainMessage(W.SET_ZEN_MODE, value, 0).sendToTarget();
|
||||
}
|
||||
|
||||
public void setExitCondition(Condition condition) {
|
||||
if (mDestroyed) return;
|
||||
mWorker.obtainMessage(W.SET_EXIT_CONDITION, condition).sendToTarget();
|
||||
}
|
||||
|
||||
public void setStreamMute(int stream, boolean mute) {
|
||||
if (mDestroyed) return;
|
||||
mWorker.obtainMessage(W.SET_STREAM_MUTE, stream, mute ? 1 : 0).sendToTarget();
|
||||
}
|
||||
|
||||
public void setStreamVolume(int stream, int level) {
|
||||
if (mDestroyed) return;
|
||||
mWorker.obtainMessage(W.SET_STREAM_VOLUME, stream, level).sendToTarget();
|
||||
}
|
||||
|
||||
public void setActiveStream(int stream) {
|
||||
if (mDestroyed) return;
|
||||
mWorker.obtainMessage(W.SET_ACTIVE_STREAM, stream, 0).sendToTarget();
|
||||
}
|
||||
|
||||
public void vibrate() {
|
||||
if (mHasVibrator) {
|
||||
mVibrator.vibrate(VIBRATE_HINT_DURATION);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasVibrator() {
|
||||
return mHasVibrator;
|
||||
}
|
||||
|
||||
private void onNotifyVisibleW(boolean visible) {
|
||||
if (mDestroyed) return;
|
||||
mAudio.notifyVolumeControllerVisible(mVolumeController, visible);
|
||||
if (!visible) {
|
||||
if (updateActiveStreamW(-1)) {
|
||||
mCallbacks.onStateChanged(mState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onUserActivityW() {
|
||||
// hook for subclasses
|
||||
}
|
||||
|
||||
private boolean checkRoutedToBluetoothW(int stream) {
|
||||
boolean changed = false;
|
||||
if (stream == AudioManager.STREAM_MUSIC) {
|
||||
final boolean routedToBluetooth =
|
||||
(mAudio.getDevicesForStream(AudioManager.STREAM_MUSIC) &
|
||||
(AudioManager.DEVICE_OUT_BLUETOOTH_A2DP |
|
||||
AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
|
||||
AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0;
|
||||
changed |= updateStreamRoutedToBluetoothW(stream, routedToBluetooth);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
private void onVolumeChangedW(int stream, int flags) {
|
||||
final boolean showUI = (flags & AudioManager.FLAG_SHOW_UI) != 0;
|
||||
final boolean fromKey = (flags & AudioManager.FLAG_FROM_KEY) != 0;
|
||||
final boolean showVibrateHint = (flags & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0;
|
||||
final boolean showSilentHint = (flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0;
|
||||
boolean changed = false;
|
||||
if (showUI) {
|
||||
changed |= updateActiveStreamW(stream);
|
||||
}
|
||||
changed |= updateStreamLevelW(stream, mAudio.getLastAudibleStreamVolume(stream));
|
||||
changed |= checkRoutedToBluetoothW(showUI ? AudioManager.STREAM_MUSIC : stream);
|
||||
if (changed) {
|
||||
mCallbacks.onStateChanged(mState);
|
||||
}
|
||||
if (showUI) {
|
||||
mCallbacks.onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
|
||||
}
|
||||
if (showVibrateHint) {
|
||||
mCallbacks.onShowVibrateHint();
|
||||
}
|
||||
if (showSilentHint) {
|
||||
mCallbacks.onShowSilentHint();
|
||||
}
|
||||
if (changed && fromKey) {
|
||||
Events.writeEvent(Events.EVENT_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean updateActiveStreamW(int activeStream) {
|
||||
if (activeStream == mState.activeStream) return false;
|
||||
mState.activeStream = activeStream;
|
||||
Events.writeEvent(Events.EVENT_ACTIVE_STREAM_CHANGED, activeStream);
|
||||
if (D.BUG) Log.d(TAG, "updateActiveStreamW " + activeStream);
|
||||
final int s = activeStream < DYNAMIC_STREAM_START_INDEX ? activeStream : -1;
|
||||
if (D.BUG) Log.d(TAG, "forceVolumeControlStream " + s);
|
||||
mAudio.forceVolumeControlStream(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
private StreamState streamStateW(int stream) {
|
||||
StreamState ss = mState.states.get(stream);
|
||||
if (ss == null) {
|
||||
ss = new StreamState();
|
||||
mState.states.put(stream, ss);
|
||||
}
|
||||
return ss;
|
||||
}
|
||||
|
||||
private void onGetStateW() {
|
||||
for (int stream : STREAMS) {
|
||||
updateStreamLevelW(stream, mAudio.getLastAudibleStreamVolume(stream));
|
||||
streamStateW(stream).levelMin = mAudio.getStreamMinVolume(stream);
|
||||
streamStateW(stream).levelMax = mAudio.getStreamMaxVolume(stream);
|
||||
updateStreamMuteW(stream, mAudio.isStreamMute(stream));
|
||||
final StreamState ss = streamStateW(stream);
|
||||
ss.muteSupported = mAudio.isStreamAffectedByMute(stream);
|
||||
ss.name = mStreamTitles[stream];
|
||||
checkRoutedToBluetoothW(stream);
|
||||
}
|
||||
updateRingerModeExternalW(mAudio.getRingerMode());
|
||||
updateZenModeW();
|
||||
updateEffectsSuppressorW(mNoMan.getEffectsSuppressor());
|
||||
updateExitConditionW();
|
||||
mCallbacks.onStateChanged(mState);
|
||||
}
|
||||
|
||||
private boolean updateStreamRoutedToBluetoothW(int stream, boolean routedToBluetooth) {
|
||||
final StreamState ss = streamStateW(stream);
|
||||
if (ss.routedToBluetooth == routedToBluetooth) return false;
|
||||
ss.routedToBluetooth = routedToBluetooth;
|
||||
if (D.BUG) Log.d(TAG, "updateStreamRoutedToBluetoothW stream=" + stream
|
||||
+ " routedToBluetooth=" + routedToBluetooth);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean updateStreamLevelW(int stream, int level) {
|
||||
final StreamState ss = streamStateW(stream);
|
||||
if (ss.level == level) return false;
|
||||
ss.level = level;
|
||||
if (isLogWorthy(stream)) {
|
||||
Events.writeEvent(Events.EVENT_LEVEL_CHANGED, stream, level);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isLogWorthy(int stream) {
|
||||
switch (stream) {
|
||||
case AudioSystem.STREAM_ALARM:
|
||||
case AudioSystem.STREAM_BLUETOOTH_SCO:
|
||||
case AudioSystem.STREAM_MUSIC:
|
||||
case AudioSystem.STREAM_RING:
|
||||
case AudioSystem.STREAM_SYSTEM:
|
||||
case AudioSystem.STREAM_VOICE_CALL:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean updateStreamMuteW(int stream, boolean muted) {
|
||||
final StreamState ss = streamStateW(stream);
|
||||
if (ss.muted == muted) return false;
|
||||
ss.muted = muted;
|
||||
if (isLogWorthy(stream)) {
|
||||
Events.writeEvent(Events.EVENT_MUTE_CHANGED, stream, muted);
|
||||
}
|
||||
if (muted && isRinger(stream)) {
|
||||
updateRingerModeInternalW(mAudio.getRingerModeInternal());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isRinger(int stream) {
|
||||
return stream == AudioManager.STREAM_RING || stream == AudioManager.STREAM_NOTIFICATION;
|
||||
}
|
||||
|
||||
private boolean updateExitConditionW() {
|
||||
final Condition exitCondition = mNoMan.getZenModeCondition();
|
||||
if (Objects.equals(mState.exitCondition, exitCondition)) return false;
|
||||
mState.exitCondition = exitCondition;
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean updateEffectsSuppressorW(ComponentName effectsSuppressor) {
|
||||
if (Objects.equals(mState.effectsSuppressor, effectsSuppressor)) return false;
|
||||
mState.effectsSuppressor = effectsSuppressor;
|
||||
mState.effectsSuppressorName = getApplicationName(mContext, mState.effectsSuppressor);
|
||||
Events.writeEvent(Events.EVENT_SUPPRESSOR_CHANGED, mState.effectsSuppressor,
|
||||
mState.effectsSuppressorName);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String getApplicationName(Context context, ComponentName component) {
|
||||
if (component == null) return null;
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
final String pkg = component.getPackageName();
|
||||
try {
|
||||
final ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
|
||||
final String rt = Objects.toString(ai.loadLabel(pm), "").trim();
|
||||
if (rt.length() > 0) {
|
||||
return rt;
|
||||
}
|
||||
} catch (NameNotFoundException e) {}
|
||||
return pkg;
|
||||
}
|
||||
|
||||
private boolean updateZenModeW() {
|
||||
final int zen = Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
|
||||
if (mState.zenMode == zen) return false;
|
||||
mState.zenMode = zen;
|
||||
Events.writeEvent(Events.EVENT_ZEN_MODE_CHANGED, zen);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean updateRingerModeExternalW(int rm) {
|
||||
if (rm == mState.ringerModeExternal) return false;
|
||||
mState.ringerModeExternal = rm;
|
||||
Events.writeEvent(Events.EVENT_EXTERNAL_RINGER_MODE_CHANGED, rm);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean updateRingerModeInternalW(int rm) {
|
||||
if (rm == mState.ringerModeInternal) return false;
|
||||
mState.ringerModeInternal = rm;
|
||||
Events.writeEvent(Events.EVENT_INTERNAL_RINGER_MODE_CHANGED, rm);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void onSetRingerModeW(int mode, boolean external) {
|
||||
if (external) {
|
||||
mAudio.setRingerMode(mode);
|
||||
} else {
|
||||
mAudio.setRingerModeInternal(mode);
|
||||
}
|
||||
}
|
||||
|
||||
private void onSetStreamMuteW(int stream, boolean mute) {
|
||||
mAudio.adjustStreamVolume(stream, mute ? AudioManager.ADJUST_MUTE
|
||||
: AudioManager.ADJUST_UNMUTE, 0);
|
||||
}
|
||||
|
||||
private void onSetStreamVolumeW(int stream, int level) {
|
||||
if (D.BUG) Log.d(TAG, "onSetStreamVolume " + stream + " level=" + level);
|
||||
if (stream >= DYNAMIC_STREAM_START_INDEX) {
|
||||
mMediaSessionsCallbacksW.setStreamVolume(stream, level);
|
||||
return;
|
||||
}
|
||||
mAudio.setStreamVolume(stream, level, 0);
|
||||
}
|
||||
|
||||
private void onSetActiveStreamW(int stream) {
|
||||
boolean changed = updateActiveStreamW(stream);
|
||||
if (changed) {
|
||||
mCallbacks.onStateChanged(mState);
|
||||
}
|
||||
}
|
||||
|
||||
private void onSetExitConditionW(Condition condition) {
|
||||
mNoMan.setZenModeCondition(condition);
|
||||
}
|
||||
|
||||
private void onSetZenModeW(int mode) {
|
||||
if (D.BUG) Log.d(TAG, "onSetZenModeW " + mode);
|
||||
mNoMan.setZenMode(mode);
|
||||
}
|
||||
|
||||
private void onDismissRequestedW(int reason) {
|
||||
mCallbacks.onDismissRequested(reason);
|
||||
}
|
||||
|
||||
public void showDndTile(boolean visible) {
|
||||
if (D.BUG) Log.d(TAG, "showDndTile");
|
||||
mContext.sendBroadcast(new Intent("com.android.systemui.dndtile.SET_VISIBLE")
|
||||
.putExtra("visible", visible));
|
||||
}
|
||||
|
||||
private final class VC extends IVolumeController.Stub {
|
||||
private final String TAG = VolumeDialogController.TAG + ".VC";
|
||||
|
||||
@Override
|
||||
public void displaySafeVolumeWarning(int flags) throws RemoteException {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
public void volumeChanged(int streamType, int flags) throws RemoteException {
|
||||
if (D.BUG) Log.d(TAG, "volumeChanged " + AudioSystem.streamToString(streamType)
|
||||
+ " " + Util.audioManagerFlagsToString(flags));
|
||||
if (mDestroyed) return;
|
||||
mWorker.obtainMessage(W.VOLUME_CHANGED, streamType, flags).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void masterMuteChanged(int flags) throws RemoteException {
|
||||
if (D.BUG) Log.d(TAG, "masterMuteChanged");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayoutDirection(int layoutDirection) throws RemoteException {
|
||||
if (D.BUG) Log.d(TAG, "setLayoutDirection");
|
||||
if (mDestroyed) return;
|
||||
mWorker.obtainMessage(W.LAYOUT_DIRECTION_CHANGED, layoutDirection, 0).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismiss() throws RemoteException {
|
||||
if (D.BUG) Log.d(TAG, "dismiss requested");
|
||||
if (mDestroyed) return;
|
||||
mWorker.obtainMessage(W.DISMISS_REQUESTED, Events.DISMISS_REASON_VOLUME_CONTROLLER, 0)
|
||||
.sendToTarget();
|
||||
mWorker.sendEmptyMessage(W.DISMISS_REQUESTED);
|
||||
}
|
||||
}
|
||||
|
||||
private final class W extends Handler {
|
||||
private static final int VOLUME_CHANGED = 1;
|
||||
private static final int DISMISS_REQUESTED = 2;
|
||||
private static final int GET_STATE = 3;
|
||||
private static final int SET_RINGER_MODE = 4;
|
||||
private static final int SET_ZEN_MODE = 5;
|
||||
private static final int SET_EXIT_CONDITION = 6;
|
||||
private static final int SET_STREAM_MUTE = 7;
|
||||
private static final int LAYOUT_DIRECTION_CHANGED = 8;
|
||||
private static final int CONFIGURATION_CHANGED = 9;
|
||||
private static final int SET_STREAM_VOLUME = 10;
|
||||
private static final int SET_ACTIVE_STREAM = 11;
|
||||
private static final int NOTIFY_VISIBLE = 12;
|
||||
private static final int USER_ACTIVITY = 13;
|
||||
|
||||
W(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case VOLUME_CHANGED: onVolumeChangedW(msg.arg1, msg.arg2); break;
|
||||
case DISMISS_REQUESTED: onDismissRequestedW(msg.arg1); break;
|
||||
case GET_STATE: onGetStateW(); break;
|
||||
case SET_RINGER_MODE: onSetRingerModeW(msg.arg1, msg.arg2 != 0); break;
|
||||
case SET_ZEN_MODE: onSetZenModeW(msg.arg1); break;
|
||||
case SET_EXIT_CONDITION: onSetExitConditionW((Condition) msg.obj); break;
|
||||
case SET_STREAM_MUTE: onSetStreamMuteW(msg.arg1, msg.arg2 != 0); break;
|
||||
case LAYOUT_DIRECTION_CHANGED: mCallbacks.onLayoutDirectionChanged(msg.arg1); break;
|
||||
case CONFIGURATION_CHANGED: mCallbacks.onConfigurationChanged(); break;
|
||||
case SET_STREAM_VOLUME: onSetStreamVolumeW(msg.arg1, msg.arg2); break;
|
||||
case SET_ACTIVE_STREAM: onSetActiveStreamW(msg.arg1); break;
|
||||
case NOTIFY_VISIBLE: onNotifyVisibleW(msg.arg1 != 0);
|
||||
case USER_ACTIVITY: onUserActivityW();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class C implements Callbacks {
|
||||
private final HashMap<Callbacks, Handler> mCallbackMap = new HashMap<>();
|
||||
|
||||
public void add(Callbacks callback, Handler handler) {
|
||||
if (callback == null || handler == null) throw new IllegalArgumentException();
|
||||
mCallbackMap.put(callback, handler);
|
||||
}
|
||||
|
||||
public void remove(Callbacks callback) {
|
||||
mCallbackMap.remove(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShowRequested(final int reason) {
|
||||
for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
|
||||
entry.getValue().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
entry.getKey().onShowRequested(reason);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismissRequested(final int reason) {
|
||||
for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
|
||||
entry.getValue().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
entry.getKey().onDismissRequested(reason);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateChanged(final State state) {
|
||||
final long time = System.currentTimeMillis();
|
||||
final State copy = state.copy();
|
||||
for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
|
||||
entry.getValue().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
entry.getKey().onStateChanged(copy);
|
||||
}
|
||||
});
|
||||
}
|
||||
Events.writeState(time, copy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayoutDirectionChanged(final int layoutDirection) {
|
||||
for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
|
||||
entry.getValue().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
entry.getKey().onLayoutDirectionChanged(layoutDirection);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged() {
|
||||
for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
|
||||
entry.getValue().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
entry.getKey().onConfigurationChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShowVibrateHint() {
|
||||
for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
|
||||
entry.getValue().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
entry.getKey().onShowVibrateHint();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShowSilentHint() {
|
||||
for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
|
||||
entry.getValue().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
entry.getKey().onShowSilentHint();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScreenOff() {
|
||||
for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
|
||||
entry.getValue().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
entry.getKey().onScreenOff();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final class SettingObserver extends ContentObserver {
|
||||
private final Uri SERVICE_URI = Settings.Secure.getUriFor(
|
||||
Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
|
||||
private final Uri ZEN_MODE_URI =
|
||||
Settings.Global.getUriFor(Settings.Global.ZEN_MODE);
|
||||
private final Uri ZEN_MODE_CONFIG_URI =
|
||||
Settings.Global.getUriFor(Settings.Global.ZEN_MODE_CONFIG_ETAG);
|
||||
|
||||
public SettingObserver(Handler handler) {
|
||||
super(handler);
|
||||
}
|
||||
|
||||
public void init() {
|
||||
mContext.getContentResolver().registerContentObserver(SERVICE_URI, false, this);
|
||||
mContext.getContentResolver().registerContentObserver(ZEN_MODE_URI, false, this);
|
||||
mContext.getContentResolver().registerContentObserver(ZEN_MODE_CONFIG_URI, false, this);
|
||||
onChange(true, SERVICE_URI);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
mContext.getContentResolver().unregisterContentObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
boolean changed = false;
|
||||
if (SERVICE_URI.equals(uri)) {
|
||||
final String setting = Settings.Secure.getString(mContext.getContentResolver(),
|
||||
Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
|
||||
final boolean enabled = setting != null && mComponent != null
|
||||
&& mComponent.equals(ComponentName.unflattenFromString(setting));
|
||||
if (enabled == mEnabled) return;
|
||||
if (enabled) {
|
||||
register();
|
||||
}
|
||||
mEnabled = enabled;
|
||||
}
|
||||
if (ZEN_MODE_URI.equals(uri)) {
|
||||
changed = updateZenModeW();
|
||||
}
|
||||
if (ZEN_MODE_CONFIG_URI.equals(uri)) {
|
||||
changed = updateExitConditionW();
|
||||
}
|
||||
if (changed) {
|
||||
mCallbacks.onStateChanged(mState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class Receiver extends BroadcastReceiver {
|
||||
|
||||
public void init() {
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
|
||||
filter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
|
||||
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
|
||||
filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
|
||||
filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION);
|
||||
filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
|
||||
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
|
||||
filter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
mContext.registerReceiver(this, filter, null, mWorker);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
mContext.unregisterReceiver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
final String action = intent.getAction();
|
||||
boolean changed = false;
|
||||
if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) {
|
||||
final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
|
||||
final int level = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
|
||||
final int oldLevel = intent
|
||||
.getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, -1);
|
||||
if (D.BUG) Log.d(TAG, "onReceive VOLUME_CHANGED_ACTION stream=" + stream
|
||||
+ " level=" + level + " oldLevel=" + oldLevel);
|
||||
changed = updateStreamLevelW(stream, level);
|
||||
} else if (action.equals(AudioManager.STREAM_DEVICES_CHANGED_ACTION)) {
|
||||
final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
|
||||
final int devices = intent
|
||||
.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, -1);
|
||||
final int oldDevices = intent
|
||||
.getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, -1);
|
||||
if (D.BUG) Log.d(TAG, "onReceive STREAM_DEVICES_CHANGED_ACTION stream="
|
||||
+ stream + " devices=" + devices + " oldDevices=" + oldDevices);
|
||||
changed = checkRoutedToBluetoothW(stream);
|
||||
} else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
|
||||
final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
|
||||
if (D.BUG) Log.d(TAG, "onReceive RINGER_MODE_CHANGED_ACTION rm="
|
||||
+ Util.ringerModeToString(rm));
|
||||
changed = updateRingerModeExternalW(rm);
|
||||
} else if (action.equals(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)) {
|
||||
final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
|
||||
if (D.BUG) Log.d(TAG, "onReceive INTERNAL_RINGER_MODE_CHANGED_ACTION rm="
|
||||
+ Util.ringerModeToString(rm));
|
||||
changed = updateRingerModeInternalW(rm);
|
||||
} else if (action.equals(AudioManager.STREAM_MUTE_CHANGED_ACTION)) {
|
||||
final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
|
||||
final boolean muted = intent
|
||||
.getBooleanExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, false);
|
||||
if (D.BUG) Log.d(TAG, "onReceive STREAM_MUTE_CHANGED_ACTION stream=" + stream
|
||||
+ " muted=" + muted);
|
||||
changed = updateStreamMuteW(stream, muted);
|
||||
} else if (action.equals(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED)) {
|
||||
if (D.BUG) Log.d(TAG, "onReceive ACTION_EFFECTS_SUPPRESSOR_CHANGED");
|
||||
changed = updateEffectsSuppressorW(mNoMan.getEffectsSuppressor());
|
||||
} else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
|
||||
if (D.BUG) Log.d(TAG, "onReceive ACTION_CONFIGURATION_CHANGED");
|
||||
mCallbacks.onConfigurationChanged();
|
||||
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
|
||||
if (D.BUG) Log.d(TAG, "onReceive ACTION_SCREEN_OFF");
|
||||
mCallbacks.onScreenOff();
|
||||
}
|
||||
if (changed) {
|
||||
mCallbacks.onStateChanged(mState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class MediaSessionsCallbacks implements MediaSessions.Callbacks {
|
||||
private final HashMap<Token, Integer> mRemoteStreams = new HashMap<>();
|
||||
|
||||
private int mNextStream = DYNAMIC_STREAM_START_INDEX;
|
||||
|
||||
@Override
|
||||
public void onRemoteUpdate(Token token, String name, PlaybackInfo pi) {
|
||||
if (!mRemoteStreams.containsKey(token)) {
|
||||
mRemoteStreams.put(token, mNextStream);
|
||||
if (D.BUG) Log.d(TAG, "onRemoteUpdate: " + name + " is stream " + mNextStream);
|
||||
mNextStream++;
|
||||
}
|
||||
final int stream = mRemoteStreams.get(token);
|
||||
boolean changed = mState.states.indexOfKey(stream) < 0;
|
||||
final StreamState ss = streamStateW(stream);
|
||||
ss.dynamic = true;
|
||||
ss.levelMin = 0;
|
||||
ss.levelMax = pi.getMaxVolume();
|
||||
if (ss.level != pi.getCurrentVolume()) {
|
||||
ss.level = pi.getCurrentVolume();
|
||||
changed = true;
|
||||
}
|
||||
if (!Objects.equals(ss.name, name)) {
|
||||
ss.name = name;
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
if (D.BUG) Log.d(TAG, "onRemoteUpdate: " + name + ": " + ss.level
|
||||
+ " of " + ss.levelMax);
|
||||
mCallbacks.onStateChanged(mState);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoteVolumeChanged(Token token, int flags) {
|
||||
final int stream = mRemoteStreams.get(token);
|
||||
final boolean showUI = (flags & AudioManager.FLAG_SHOW_UI) != 0;
|
||||
boolean changed = updateActiveStreamW(stream);
|
||||
if (showUI) {
|
||||
changed |= checkRoutedToBluetoothW(AudioManager.STREAM_MUSIC);
|
||||
}
|
||||
if (changed) {
|
||||
mCallbacks.onStateChanged(mState);
|
||||
}
|
||||
if (showUI) {
|
||||
mCallbacks.onShowRequested(Events.SHOW_REASON_REMOTE_VOLUME_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoteRemoved(Token token) {
|
||||
final int stream = mRemoteStreams.get(token);
|
||||
mState.states.remove(stream);
|
||||
if (mState.activeStream == stream) {
|
||||
updateActiveStreamW(-1);
|
||||
}
|
||||
mCallbacks.onStateChanged(mState);
|
||||
}
|
||||
|
||||
public void setStreamVolume(int stream, int level) {
|
||||
final Token t = findToken(stream);
|
||||
if (t == null) {
|
||||
Log.w(TAG, "setStreamVolume: No token found for stream: " + stream);
|
||||
return;
|
||||
}
|
||||
mMediaSessions.setVolume(t, level);
|
||||
}
|
||||
|
||||
private Token findToken(int stream) {
|
||||
for (Map.Entry<Token, Integer> entry : mRemoteStreams.entrySet()) {
|
||||
if (entry.getValue().equals(stream)) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class StreamState {
|
||||
public boolean dynamic;
|
||||
public int level;
|
||||
public int levelMin;
|
||||
public int levelMax;
|
||||
public boolean muted;
|
||||
public boolean muteSupported;
|
||||
public String name;
|
||||
public boolean routedToBluetooth;
|
||||
|
||||
public StreamState copy() {
|
||||
final StreamState rt = new StreamState();
|
||||
rt.dynamic = dynamic;
|
||||
rt.level = level;
|
||||
rt.levelMin = levelMin;
|
||||
rt.levelMax = levelMax;
|
||||
rt.muted = muted;
|
||||
rt.muteSupported = muteSupported;
|
||||
rt.name = name;
|
||||
rt.routedToBluetooth = routedToBluetooth;
|
||||
return rt;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class State {
|
||||
public static int NO_ACTIVE_STREAM = -1;
|
||||
|
||||
public final SparseArray<StreamState> states = new SparseArray<StreamState>();
|
||||
|
||||
public int ringerModeInternal;
|
||||
public int ringerModeExternal;
|
||||
public int zenMode;
|
||||
public ComponentName effectsSuppressor;
|
||||
public String effectsSuppressorName;
|
||||
public Condition exitCondition;
|
||||
public int activeStream = NO_ACTIVE_STREAM;
|
||||
|
||||
public State copy() {
|
||||
final State rt = new State();
|
||||
for (int i = 0; i < states.size(); i++) {
|
||||
rt.states.put(states.keyAt(i), states.valueAt(i).copy());
|
||||
}
|
||||
rt.ringerModeExternal = ringerModeExternal;
|
||||
rt.ringerModeInternal = ringerModeInternal;
|
||||
rt.zenMode = zenMode;
|
||||
if (effectsSuppressor != null) rt.effectsSuppressor = effectsSuppressor.clone();
|
||||
rt.effectsSuppressorName = effectsSuppressorName;
|
||||
if (exitCondition != null) rt.exitCondition = exitCondition.copy();
|
||||
rt.activeStream = activeStream;
|
||||
return rt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("{");
|
||||
for (int i = 0; i < states.size(); i++) {
|
||||
if (i > 0) sb.append(',');
|
||||
final int stream = states.keyAt(i);
|
||||
final StreamState ss = states.valueAt(i);
|
||||
sb.append(AudioSystem.streamToString(stream)).append(":").append(ss.level)
|
||||
.append("[").append(ss.levelMin).append("..").append(ss.levelMax);
|
||||
if (ss.muted) sb.append(" [MUTED]");
|
||||
}
|
||||
sb.append(",ringerModeExternal:").append(ringerModeExternal);
|
||||
sb.append(",ringerModeInternal:").append(ringerModeInternal);
|
||||
sb.append(",zenMode:").append(zenMode);
|
||||
sb.append(",effectsSuppressor:").append(effectsSuppressor);
|
||||
sb.append(",effectsSuppressorName:").append(effectsSuppressorName);
|
||||
sb.append(",exitCondition:").append(exitCondition);
|
||||
sb.append(",activeStream:").append(activeStream);
|
||||
return sb.append('}').toString();
|
||||
}
|
||||
}
|
||||
|
||||
public interface Callbacks {
|
||||
void onShowRequested(int reason);
|
||||
void onDismissRequested(int reason);
|
||||
void onStateChanged(State state);
|
||||
void onLayoutDirectionChanged(int layoutDirection);
|
||||
void onConfigurationChanged();
|
||||
void onShowVibrateHint();
|
||||
void onShowSilentHint();
|
||||
void onScreenOff();
|
||||
}
|
||||
}
|
||||
@@ -384,7 +384,7 @@ public class VolumePanel extends Handler implements DemoMode {
|
||||
final Window window = mDialog.getWindow();
|
||||
window.requestFeature(Window.FEATURE_NO_TITLE);
|
||||
mDialog.setCanceledOnTouchOutside(true);
|
||||
mDialog.setContentView(com.android.systemui.R.layout.volume_dialog);
|
||||
mDialog.setContentView(com.android.systemui.R.layout.volume_panel_dialog);
|
||||
mDialog.setOnDismissListener(new OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.volume;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.media.AudioManager;
|
||||
import android.media.IRemoteVolumeController;
|
||||
import android.media.IVolumeController;
|
||||
import android.media.VolumePolicy;
|
||||
import android.media.session.ISessionController;
|
||||
import android.media.session.MediaController;
|
||||
import android.media.session.MediaSessionManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SystemUI;
|
||||
import com.android.systemui.keyguard.KeyguardViewMediator;
|
||||
import com.android.systemui.qs.tiles.DndTile;
|
||||
import com.android.systemui.statusbar.phone.PhoneStatusBar;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Implementation of VolumeComponent backed by the old volume panel.
|
||||
*/
|
||||
public class VolumePanelComponent implements VolumeComponent {
|
||||
|
||||
private final SystemUI mSysui;
|
||||
private final Context mContext;
|
||||
private final Handler mHandler;
|
||||
private final VolumeController mVolumeController;
|
||||
private final RemoteVolumeController mRemoteVolumeController;
|
||||
private final AudioManager mAudioManager;
|
||||
private final MediaSessionManager mMediaSessionManager;
|
||||
|
||||
private VolumePanel mPanel;
|
||||
private int mDismissDelay;
|
||||
|
||||
public VolumePanelComponent(SystemUI sysui, Context context, Handler handler,
|
||||
ZenModeController controller) {
|
||||
mSysui = sysui;
|
||||
mContext = context;
|
||||
mHandler = handler;
|
||||
mAudioManager = context.getSystemService(AudioManager.class);
|
||||
mMediaSessionManager = context.getSystemService(MediaSessionManager.class);
|
||||
mVolumeController = new VolumeController();
|
||||
mRemoteVolumeController = new RemoteVolumeController();
|
||||
mDismissDelay = mContext.getResources().getInteger(R.integer.volume_panel_dismiss_delay);
|
||||
mPanel = new VolumePanel(mContext, controller);
|
||||
mPanel.setCallback(new VolumePanel.Callback() {
|
||||
@Override
|
||||
public void onZenSettings() {
|
||||
mHandler.removeCallbacks(mStartZenSettings);
|
||||
mHandler.post(mStartZenSettings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInteraction() {
|
||||
final KeyguardViewMediator kvm = mSysui.getComponent(KeyguardViewMediator.class);
|
||||
if (kvm != null) {
|
||||
kvm.userActivity();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVisible(boolean visible) {
|
||||
if (mAudioManager != null && mVolumeController != null) {
|
||||
mAudioManager.notifyVolumeControllerVisible(mVolumeController, visible);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
if (mPanel != null) {
|
||||
mPanel.dump(fd, pw, args);
|
||||
}
|
||||
}
|
||||
|
||||
public void register() {
|
||||
mAudioManager.setVolumeController(mVolumeController);
|
||||
mAudioManager.setVolumePolicy(VolumePolicy.DEFAULT);
|
||||
mMediaSessionManager.setRemoteVolumeController(mRemoteVolumeController);
|
||||
DndTile.setVisible(mContext, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
if (mPanel != null) {
|
||||
mPanel.onConfigurationChanged(newConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZenModeController getZenController() {
|
||||
return mPanel.getZenController();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchDemoCommand(String command, Bundle args) {
|
||||
mPanel.dispatchDemoCommand(command, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismissNow() {
|
||||
mPanel.postDismiss(0);
|
||||
}
|
||||
|
||||
private final Runnable mStartZenSettings = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mSysui.getComponent(PhoneStatusBar.class).startActivityDismissingKeyguard(
|
||||
ZenModePanel.ZEN_SETTINGS, true /* onlyProvisioned */, true /* dismissShade */);
|
||||
mPanel.postDismiss(mDismissDelay);
|
||||
}
|
||||
};
|
||||
|
||||
private final class RemoteVolumeController extends IRemoteVolumeController.Stub {
|
||||
@Override
|
||||
public void remoteVolumeChanged(ISessionController binder, int flags)
|
||||
throws RemoteException {
|
||||
MediaController controller = new MediaController(mContext, binder);
|
||||
mPanel.postRemoteVolumeChanged(controller, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRemoteController(ISessionController session) throws RemoteException {
|
||||
mPanel.postRemoteSliderVisibility(session != null);
|
||||
// TODO stash default session in case the slider can be opened other
|
||||
// than by remoteVolumeChanged.
|
||||
}
|
||||
}
|
||||
|
||||
/** For now, simply host an unmodified base volume panel in this process. */
|
||||
private final class VolumeController extends IVolumeController.Stub {
|
||||
|
||||
@Override
|
||||
public void displaySafeVolumeWarning(int flags) throws RemoteException {
|
||||
mPanel.postDisplaySafeVolumeWarning(flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void volumeChanged(int streamType, int flags)
|
||||
throws RemoteException {
|
||||
mPanel.postVolumeChanged(streamType, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void masterMuteChanged(int flags) throws RemoteException {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayoutDirection(int layoutDirection)
|
||||
throws RemoteException {
|
||||
mPanel.postLayoutDirection(layoutDirection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismiss() throws RemoteException {
|
||||
dismissNow();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,25 +29,17 @@ import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.media.AudioManager;
|
||||
import android.media.IRemoteVolumeController;
|
||||
import android.media.IVolumeController;
|
||||
import android.media.VolumePolicy;
|
||||
import android.media.session.ISessionController;
|
||||
import android.media.session.MediaController;
|
||||
import android.media.session.MediaSessionManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemProperties;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SystemUI;
|
||||
import com.android.systemui.keyguard.KeyguardViewMediator;
|
||||
import com.android.systemui.qs.tiles.DndTile;
|
||||
import com.android.systemui.statusbar.ServiceMonitor;
|
||||
import com.android.systemui.statusbar.phone.PhoneStatusBar;
|
||||
import com.android.systemui.statusbar.phone.SystemUIDialog;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
|
||||
@@ -59,6 +51,8 @@ public class VolumeUI extends SystemUI {
|
||||
private static final String TAG = "VolumeUI";
|
||||
private static boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
private static final boolean USE_OLD_VOLUME = SystemProperties.getBoolean("volume.old", false);
|
||||
|
||||
private final Handler mHandler = new Handler();
|
||||
private final Receiver mReceiver = new Receiver();
|
||||
private final RestorationNotification mRestorationNotification = new RestorationNotification();
|
||||
@@ -67,12 +61,10 @@ public class VolumeUI extends SystemUI {
|
||||
private AudioManager mAudioManager;
|
||||
private NotificationManager mNotificationManager;
|
||||
private MediaSessionManager mMediaSessionManager;
|
||||
private VolumeController mVolumeController;
|
||||
private RemoteVolumeController mRemoteVolumeController;
|
||||
private ServiceMonitor mVolumeControllerService;
|
||||
|
||||
private VolumePanel mPanel;
|
||||
private int mDismissDelay;
|
||||
private VolumePanelComponent mOldVolume;
|
||||
private VolumeDialogComponent mNewVolume;
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
@@ -83,10 +75,10 @@ public class VolumeUI extends SystemUI {
|
||||
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
mMediaSessionManager = (MediaSessionManager) mContext
|
||||
.getSystemService(Context.MEDIA_SESSION_SERVICE);
|
||||
initPanel();
|
||||
mVolumeController = new VolumeController();
|
||||
mRemoteVolumeController = new RemoteVolumeController();
|
||||
putComponent(VolumeComponent.class, mVolumeController);
|
||||
final ZenModeController zenController = new ZenModeControllerImpl(mContext, mHandler);
|
||||
mOldVolume = new VolumePanelComponent(this, mContext, mHandler, zenController);
|
||||
mNewVolume = new VolumeDialogComponent(this, mContext, null, zenController);
|
||||
putComponent(VolumeComponent.class, getVolumeComponent());
|
||||
mReceiver.start();
|
||||
mVolumeControllerService = new ServiceMonitor(TAG, LOGD,
|
||||
mContext, Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT,
|
||||
@@ -94,30 +86,30 @@ public class VolumeUI extends SystemUI {
|
||||
mVolumeControllerService.start();
|
||||
}
|
||||
|
||||
private VolumeComponent getVolumeComponent() {
|
||||
return USE_OLD_VOLUME ? mOldVolume : mNewVolume;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
if (mPanel != null) {
|
||||
mPanel.onConfigurationChanged(newConfig);
|
||||
}
|
||||
if (!mEnabled) return;
|
||||
getVolumeComponent().onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.print("mEnabled="); pw.println(mEnabled);
|
||||
if (!mEnabled) return;
|
||||
pw.print("mVolumeControllerService="); pw.println(mVolumeControllerService.getComponent());
|
||||
if (mPanel != null) {
|
||||
mPanel.dump(fd, pw, args);
|
||||
}
|
||||
getVolumeComponent().dump(fd, pw, args);
|
||||
}
|
||||
|
||||
private void setVolumeController(boolean register) {
|
||||
private void setDefaultVolumeController(boolean register) {
|
||||
if (register) {
|
||||
if (LOGD) Log.d(TAG, "Registering default volume controller");
|
||||
mAudioManager.setVolumeController(mVolumeController);
|
||||
mAudioManager.setVolumePolicy(VolumePolicy.DEFAULT);
|
||||
mMediaSessionManager.setRemoteVolumeController(mRemoteVolumeController);
|
||||
DndTile.setVisible(mContext, false);
|
||||
if (LOGD) Log.d(TAG, "Registering default volume controller");
|
||||
getVolumeComponent().register();
|
||||
} else {
|
||||
if (LOGD) Log.d(TAG, "Unregistering default volume controller");
|
||||
mAudioManager.setVolumeController(null);
|
||||
@@ -125,33 +117,6 @@ public class VolumeUI extends SystemUI {
|
||||
}
|
||||
}
|
||||
|
||||
private void initPanel() {
|
||||
mDismissDelay = mContext.getResources().getInteger(R.integer.volume_panel_dismiss_delay);
|
||||
mPanel = new VolumePanel(mContext, new ZenModeControllerImpl(mContext, mHandler));
|
||||
mPanel.setCallback(new VolumePanel.Callback() {
|
||||
@Override
|
||||
public void onZenSettings() {
|
||||
mHandler.removeCallbacks(mStartZenSettings);
|
||||
mHandler.post(mStartZenSettings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInteraction() {
|
||||
final KeyguardViewMediator kvm = getComponent(KeyguardViewMediator.class);
|
||||
if (kvm != null) {
|
||||
kvm.userActivity();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVisible(boolean visible) {
|
||||
if (mAudioManager != null && mVolumeController != null) {
|
||||
mAudioManager.notifyVolumeControllerVisible(mVolumeController, visible);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String getAppLabel(ComponentName component) {
|
||||
final String pkg = component.getPackageName();
|
||||
try {
|
||||
@@ -179,83 +144,11 @@ public class VolumeUI extends SystemUI {
|
||||
d.show();
|
||||
}
|
||||
|
||||
private final Runnable mStartZenSettings = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
getComponent(PhoneStatusBar.class).startActivityDismissingKeyguard(
|
||||
ZenModePanel.ZEN_SETTINGS, true /* onlyProvisioned */, true /* dismissShade */);
|
||||
mPanel.postDismiss(mDismissDelay);
|
||||
}
|
||||
};
|
||||
|
||||
/** For now, simply host an unmodified base volume panel in this process. */
|
||||
private final class VolumeController extends IVolumeController.Stub implements VolumeComponent {
|
||||
|
||||
@Override
|
||||
public void displaySafeVolumeWarning(int flags) throws RemoteException {
|
||||
mPanel.postDisplaySafeVolumeWarning(flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void volumeChanged(int streamType, int flags)
|
||||
throws RemoteException {
|
||||
mPanel.postVolumeChanged(streamType, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void masterMuteChanged(int flags) throws RemoteException {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayoutDirection(int layoutDirection)
|
||||
throws RemoteException {
|
||||
mPanel.postLayoutDirection(layoutDirection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismiss() throws RemoteException {
|
||||
dismissNow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZenModeController getZenController() {
|
||||
return mPanel.getZenController();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchDemoCommand(String command, Bundle args) {
|
||||
mPanel.dispatchDemoCommand(command, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismissNow() {
|
||||
mPanel.postDismiss(0);
|
||||
}
|
||||
}
|
||||
|
||||
private final class RemoteVolumeController extends IRemoteVolumeController.Stub {
|
||||
|
||||
@Override
|
||||
public void remoteVolumeChanged(ISessionController binder, int flags)
|
||||
throws RemoteException {
|
||||
MediaController controller = new MediaController(mContext, binder);
|
||||
mPanel.postRemoteVolumeChanged(controller, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRemoteController(ISessionController session) throws RemoteException {
|
||||
mPanel.postRemoteSliderVisibility(session != null);
|
||||
// TODO stash default session in case the slider can be opened other
|
||||
// than by remoteVolumeChanged.
|
||||
}
|
||||
}
|
||||
|
||||
private final class ServiceMonitorCallbacks implements ServiceMonitor.Callbacks {
|
||||
@Override
|
||||
public void onNoService() {
|
||||
if (LOGD) Log.d(TAG, "onNoService");
|
||||
setVolumeController(true);
|
||||
setDefaultVolumeController(true);
|
||||
mRestorationNotification.hide();
|
||||
if (!mVolumeControllerService.isPackageAvailable()) {
|
||||
mVolumeControllerService.setComponent(null);
|
||||
@@ -267,8 +160,8 @@ public class VolumeUI extends SystemUI {
|
||||
if (LOGD) Log.d(TAG, "onServiceStartAttempt");
|
||||
// poke the setting to update the uid
|
||||
mVolumeControllerService.setComponent(mVolumeControllerService.getComponent());
|
||||
setVolumeController(false);
|
||||
mVolumeController.dismissNow();
|
||||
setDefaultVolumeController(false);
|
||||
getVolumeComponent().dismissNow();
|
||||
mRestorationNotification.show();
|
||||
return 0;
|
||||
}
|
||||
|
||||
216
packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
Normal file
216
packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.systemui.volume;
|
||||
|
||||
import android.animation.LayoutTransition;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.provider.Settings.Global;
|
||||
import android.service.notification.Condition;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
|
||||
/**
|
||||
* Switch bar + zen mode panel (conditions) attached to the bottom of the volume dialog.
|
||||
*/
|
||||
public class ZenFooter extends LinearLayout {
|
||||
private static final String TAG = Util.logTag(ZenFooter.class);
|
||||
|
||||
private final Context mContext;
|
||||
private final float mSecondaryAlpha;
|
||||
private final LayoutTransition mLayoutTransition;
|
||||
|
||||
private ZenModeController mController;
|
||||
private Switch mSwitch;
|
||||
private ZenModePanel mZenModePanel;
|
||||
private View mZenModePanelButtons;
|
||||
private View mZenModePanelMoreButton;
|
||||
private View mZenModePanelDoneButton;
|
||||
private View mSwitchBar;
|
||||
private View mSwitchBarIcon;
|
||||
private View mSummary;
|
||||
private TextView mSummaryLine1;
|
||||
private TextView mSummaryLine2;
|
||||
private boolean mFooterExpanded;
|
||||
private int mZen = -1;
|
||||
private Callback mCallback;
|
||||
|
||||
public ZenFooter(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mContext = context;
|
||||
mSecondaryAlpha = getFloat(context.getResources(), R.dimen.volume_secondary_alpha);
|
||||
mLayoutTransition = new LayoutTransition();
|
||||
mLayoutTransition.setDuration(new ValueAnimator().getDuration() / 2);
|
||||
mLayoutTransition.disableTransitionType(LayoutTransition.DISAPPEARING);
|
||||
mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
|
||||
}
|
||||
|
||||
private static float getFloat(Resources r, int resId) {
|
||||
final TypedValue tv = new TypedValue();
|
||||
r.getValue(resId, tv, true);
|
||||
return tv.getFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mSwitchBar = findViewById(R.id.volume_zen_switch_bar);
|
||||
mSwitchBarIcon = findViewById(R.id.volume_zen_switch_bar_icon);
|
||||
mSwitch = (Switch) findViewById(R.id.volume_zen_switch);
|
||||
mZenModePanel = (ZenModePanel) findViewById(R.id.zen_mode_panel);
|
||||
mZenModePanelButtons = findViewById(R.id.volume_zen_mode_panel_buttons);
|
||||
mZenModePanelMoreButton = findViewById(R.id.volume_zen_mode_panel_more);
|
||||
mZenModePanelDoneButton = findViewById(R.id.volume_zen_mode_panel_done);
|
||||
mSummary = findViewById(R.id.volume_zen_panel_summary);
|
||||
mSummaryLine1 = (TextView) findViewById(R.id.volume_zen_panel_summary_line_1);
|
||||
mSummaryLine2 = (TextView) findViewById(R.id.volume_zen_panel_summary_line_2);
|
||||
}
|
||||
|
||||
public void init(ZenModeController controller, Callback callback) {
|
||||
mCallback = callback;
|
||||
mController = controller;
|
||||
mZenModePanel.init(controller);
|
||||
mZenModePanel.setEmbedded(true);
|
||||
mSwitch.setOnCheckedChangeListener(mCheckedListener);
|
||||
mController.addCallback(new ZenModeController.Callback() {
|
||||
@Override
|
||||
public void onZenChanged(int zen) {
|
||||
setZen(zen);
|
||||
}
|
||||
@Override
|
||||
public void onExitConditionChanged(Condition exitCondition) {
|
||||
update();
|
||||
}
|
||||
});
|
||||
mSwitchBar.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mSwitch.setChecked(!mSwitch.isChecked());
|
||||
}
|
||||
});
|
||||
mZenModePanelMoreButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (mCallback != null) {
|
||||
mCallback.onSettingsClicked();
|
||||
}
|
||||
}
|
||||
});
|
||||
mZenModePanelDoneButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (mCallback != null) {
|
||||
mCallback.onDoneClicked();
|
||||
}
|
||||
}
|
||||
});
|
||||
mZen = mController.getZen();
|
||||
update();
|
||||
}
|
||||
|
||||
private void setZen(int zen) {
|
||||
if (mZen == zen) return;
|
||||
mZen = zen;
|
||||
update();
|
||||
}
|
||||
|
||||
public boolean isZen() {
|
||||
return isZenPriority() || isZenNone();
|
||||
}
|
||||
|
||||
private boolean isZenPriority() {
|
||||
return mZen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
|
||||
}
|
||||
|
||||
private boolean isZenNone() {
|
||||
return mZen == Global.ZEN_MODE_NO_INTERRUPTIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
setLayoutTransition(null);
|
||||
setFooterExpanded(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
setLayoutTransition(mLayoutTransition);
|
||||
}
|
||||
|
||||
private boolean setFooterExpanded(boolean expanded) {
|
||||
if (mFooterExpanded == expanded) return false;
|
||||
mFooterExpanded = expanded;
|
||||
update();
|
||||
if (mCallback != null) {
|
||||
mCallback.onFooterExpanded();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isFooterExpanded() {
|
||||
return mFooterExpanded;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
final boolean isZen = isZen();
|
||||
mSwitch.setOnCheckedChangeListener(null);
|
||||
mSwitch.setChecked(isZen);
|
||||
mSwitch.setOnCheckedChangeListener(mCheckedListener);
|
||||
Util.setVisOrGone(mZenModePanel, isZen && mFooterExpanded);
|
||||
Util.setVisOrGone(mZenModePanelButtons, isZen && mFooterExpanded);
|
||||
Util.setVisOrGone(mSummary, isZen && !mFooterExpanded);
|
||||
mSwitchBarIcon.setAlpha(isZen ? 1 : mSecondaryAlpha);
|
||||
final String line1 =
|
||||
isZenPriority() ? mContext.getString(R.string.interruption_level_priority)
|
||||
: isZenNone() ? mContext.getString(R.string.interruption_level_none)
|
||||
: null;
|
||||
Util.setText(mSummaryLine1, line1);
|
||||
Util.setText(mSummaryLine2, mZenModePanel.getExitConditionText());
|
||||
}
|
||||
|
||||
private final OnCheckedChangeListener mCheckedListener = new OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
if (D.BUG) Log.d(TAG, "onCheckedChanged " + isChecked);
|
||||
if (isChecked != isZen()) {
|
||||
final int newZen = isChecked ? Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
|
||||
: Global.ZEN_MODE_OFF;
|
||||
mZen = newZen; // this one's optimistic
|
||||
setFooterExpanded(isChecked);
|
||||
mController.setZen(newZen);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public interface Callback {
|
||||
void onFooterExpanded();
|
||||
void onSettingsClicked();
|
||||
void onDoneClicked();
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.content.res.Resources;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Handler;
|
||||
@@ -150,6 +149,7 @@ public class ZenModePanel extends LinearLayout {
|
||||
if (mEmbedded == embedded) return;
|
||||
mEmbedded = embedded;
|
||||
mZenButtonsContainer.setLayoutTransition(mEmbedded ? null : newLayoutTransition(null));
|
||||
setLayoutTransition(mEmbedded ? null : newLayoutTransition(null));
|
||||
if (mEmbedded) {
|
||||
mZenButtonsContainer.setBackground(null);
|
||||
} else {
|
||||
@@ -166,12 +166,10 @@ public class ZenModePanel extends LinearLayout {
|
||||
super.onFinishInflate();
|
||||
|
||||
mZenButtons = (SegmentedButtons) findViewById(R.id.zen_buttons);
|
||||
mZenButtons.addButton(R.string.interruption_level_none, R.drawable.ic_zen_none,
|
||||
Global.ZEN_MODE_NO_INTERRUPTIONS);
|
||||
mZenButtons.addButton(R.string.interruption_level_priority, R.drawable.ic_zen_important,
|
||||
mZenButtons.addButton(R.string.interruption_level_none, Global.ZEN_MODE_NO_INTERRUPTIONS);
|
||||
mZenButtons.addButton(R.string.interruption_level_priority,
|
||||
Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
|
||||
mZenButtons.addButton(R.string.interruption_level_all, R.drawable.ic_zen_all,
|
||||
Global.ZEN_MODE_OFF);
|
||||
mZenButtons.addButton(R.string.interruption_level_all, Global.ZEN_MODE_OFF);
|
||||
mZenButtons.setCallback(mZenButtonsCallback);
|
||||
|
||||
mZenButtonsContainer = (ViewGroup) findViewById(R.id.zen_buttons_container);
|
||||
@@ -275,6 +273,7 @@ public class ZenModePanel extends LinearLayout {
|
||||
|
||||
private void setExpanded(boolean expanded) {
|
||||
if (expanded == mExpanded) return;
|
||||
if (DEBUG) Log.d(mTag, "setExpanded " + expanded);
|
||||
mExpanded = expanded;
|
||||
if (mExpanded) {
|
||||
ensureSelection();
|
||||
@@ -358,6 +357,10 @@ public class ZenModePanel extends LinearLayout {
|
||||
return condition == null ? null : condition.copy();
|
||||
}
|
||||
|
||||
public String getExitConditionText() {
|
||||
return mExitConditionText;
|
||||
}
|
||||
|
||||
private void refreshExitConditionText() {
|
||||
if (mExitCondition == null) {
|
||||
mExitConditionText = foreverSummary();
|
||||
@@ -428,7 +431,7 @@ public class ZenModePanel extends LinearLayout {
|
||||
mZenSubheadExpanded.setVisibility(expanded ? VISIBLE : GONE);
|
||||
mZenSubheadCollapsed.setVisibility(!expanded ? VISIBLE : GONE);
|
||||
mMoreSettings.setVisibility(zenImportant && expanded ? VISIBLE : GONE);
|
||||
mZenConditions.setVisibility(!zenOff && expanded ? VISIBLE : GONE);
|
||||
mZenConditions.setVisibility(mEmbedded || !zenOff && expanded ? VISIBLE : GONE);
|
||||
|
||||
if (zenNone) {
|
||||
mZenSubheadExpanded.setText(R.string.zen_no_interruptions_with_warning);
|
||||
|
||||
Reference in New Issue
Block a user