diff options
| author | Maitreya29 <maitreyapatni30@gmail.com> | 2021-06-21 19:05:52 +0530 |
|---|---|---|
| committer | Semavi Ulusoy <doc.divxm@gmail.com> | 2021-09-08 09:31:55 +0300 |
| commit | beef9105cb4e20cc4a8220c8bc81cfb54b1b6946 (patch) | |
| tree | 6caa2a07521c382d559776cd2261f55bdb2e5ff0 | |
| parent | 9874e2a3b4b4e93871f1521522dc02e96e995082 (diff) | |
Plugins: Introduce OOS Volume Panel [3/3]
spkal01: Make it a plugin + adapt for per app volume
Co-authored-by: spkal01 <kalligeross@gmail.com>
Signed-off-by: Stallix <joey@evolution-x.org>
Change-Id: I9b47f2e42973308efca52405c7af42aaacab77bf
39 files changed, 2482 insertions, 0 deletions
diff --git a/OosPanel/Android.bp b/OosPanel/Android.bp new file mode 100644 index 0000000..d450a6f --- /dev/null +++ b/OosPanel/Android.bp @@ -0,0 +1,20 @@ +android_app { + + name: "OosPanel", + + static_libs: [ + "VolumePluginCommon", + ], + + resource_dirs: ["res"], + + certificate: "platform", + optimize: { + enabled: false, + proguard_flags_files: ["proguard.flags"], + }, + platform_apis: true, + + srcs: ["src/**/*.java"], + +} diff --git a/OosPanel/AndroidManifest.xml b/OosPanel/AndroidManifest.xml new file mode 100644 index 0000000..bce17d0 --- /dev/null +++ b/OosPanel/AndroidManifest.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2015 The Android Open Source Project + Copyright (C) 2020 The Potato Open Sauce 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="co.potatoproject.plugin.volume.oos"> + + <uses-permission android:name="com.android.systemui.permission.PLUGIN" /> + + <application + android:label="@string/plugin_label"> + <service android:name=".VolumeDialogImpl" + android:label="@string/plugin_label"> + <intent-filter> + <action android:name="com.android.systemui.action.PLUGIN_VOLUME" /> + </intent-filter> + </service> + + <provider + android:name="androidx.lifecycle.ProcessLifecycleOwnerInitializer" + android:authorities="co.potatoproject.plugin.volume.oos" + tools:replace="android:authorities" + android:exported="false" + android:multiprocess="true" /> + </application> + +</manifest> diff --git a/OosPanel/proguard.flags b/OosPanel/proguard.flags new file mode 100644 index 0000000..4f6fe1f --- /dev/null +++ b/OosPanel/proguard.flags @@ -0,0 +1,2 @@ +-keep @com.android.systemui.plugins.Requires public class * +-keep class javax.inject.** { *; }
\ No newline at end of file diff --git a/OosPanel/res/color-night/caption_tint_color_selector.xml b/OosPanel/res/color-night/caption_tint_color_selector.xml new file mode 100644 index 0000000..f147165 --- /dev/null +++ b/OosPanel/res/color-night/caption_tint_color_selector.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:sysui="http://schemas.android.com/apk/res-auto"> + <item sysui:optedOut="true" + android:color="?android:attr/colorButtonNormal"/> + + <item android:color="#FFFFFF"/> +</selector>
\ No newline at end of file diff --git a/OosPanel/res/color-night/ninja_tint_color_selector.xml b/OosPanel/res/color-night/ninja_tint_color_selector.xml new file mode 100644 index 0000000..cf3b82f --- /dev/null +++ b/OosPanel/res/color-night/ninja_tint_color_selector.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:color="?android:attr/colorButtonNormal"/> + + <item android:color="#FFFFFF"/> +</selector>
\ No newline at end of file diff --git a/OosPanel/res/color/caption_tint_color_selector.xml b/OosPanel/res/color/caption_tint_color_selector.xml new file mode 100644 index 0000000..2221bb9 --- /dev/null +++ b/OosPanel/res/color/caption_tint_color_selector.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:sysui="http://schemas.android.com/apk/res-auto"> + <item sysui:optedOut="true" + android:color="?android:attr/colorButtonNormal"/> + + <item android:color="#000000"/> +</selector>
\ No newline at end of file diff --git a/OosPanel/res/color/ninja_tint_color_selector.xml b/OosPanel/res/color/ninja_tint_color_selector.xml new file mode 100644 index 0000000..8d38ddd --- /dev/null +++ b/OosPanel/res/color/ninja_tint_color_selector.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:color="?android:attr/colorButtonNormal"/> + + <item android:color="#000000"/> +</selector>
\ No newline at end of file diff --git a/OosPanel/res/drawable-night/circleboi.xml b/OosPanel/res/drawable-night/circleboi.xml new file mode 100644 index 0000000..8523a46 --- /dev/null +++ b/OosPanel/res/drawable-night/circleboi.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> + +<shape + xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="oval"> + <solid + android:color="#121212"/> + + <size + android:width="41dp" + android:height="41dp"/> + +</shape>
\ No newline at end of file diff --git a/OosPanel/res/drawable-night/ic_volume_media.xml b/OosPanel/res/drawable-night/ic_volume_media.xml new file mode 100644 index 0000000..798a936 --- /dev/null +++ b/OosPanel/res/drawable-night/ic_volume_media.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:aapt="http://schemas.android.com/aapt" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"> + <path android:fillColor="#FFFFFF" android:pathData="M13.9004,1.6001H12.1001V14.8363C11.2314,14.1065 10.1345,13.7042 9,13.6992C8.0308,13.6992 7.0834,13.9866 6.2775,14.5251C5.4716,15.0635 4.8435,15.8289 4.4726,16.7243C4.1017,17.6197 4.0047,18.605 4.1938,19.5556C4.3829,20.5062 4.8496,21.3794 5.5349,22.0647C6.2202,22.75 7.0934,23.2168 8.044,23.4058C8.9946,23.5949 9.9799,23.4979 10.8753,23.127C11.7707,22.7561 12.5361,22.128 13.0745,21.3221C13.613,20.5163 13.9004,19.5688 13.9004,18.5996V5.229C15.6151,6.6594 17.7673,7.4607 20,7.5V5.7002C17.2373,5.7002 13.9004,3.8711 13.9004,1.6001ZM9,21.6992C8.387,21.6991 7.7877,21.5173 7.2781,21.1766C6.7684,20.836 6.3712,20.3518 6.1367,19.7854C5.9022,19.219 5.8408,18.5958 5.9605,17.9946C6.0802,17.3934 6.3754,16.8411 6.8089,16.4077C7.2424,15.9742 7.7947,15.6791 8.396,15.5595C8.9972,15.44 9.6204,15.5014 10.1868,15.736C10.7531,15.9706 11.2372,16.3679 11.5778,16.8776C11.9183,17.3873 12.1001,17.9866 12.1001,18.5996C12.0991,19.4214 11.7721,20.2093 11.191,20.7904C10.6098,21.3715 9.8218,21.6983 9,21.6992Z"/> +</vector> diff --git a/OosPanel/res/drawable-night/ic_volume_media_bt.xml b/OosPanel/res/drawable-night/ic_volume_media_bt.xml new file mode 100644 index 0000000..c0c7b9f --- /dev/null +++ b/OosPanel/res/drawable-night/ic_volume_media_bt.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:aapt="http://schemas.android.com/aapt" android:height="@dimen/op_volume_dialog_icon_size" android:width="@dimen/op_volume_dialog_icon_size" android:viewportWidth="24" android:viewportHeight="24"> + <path android:fillColor="#FFFFFF" android:pathData="M10.75,1H9.25V14.55A4.74,4.74,0,1,0,10.75,18V3.83A9.79,9.79,0,0,0,17,6.75V5.25C14.19,5.25,10.75,2.4,10.75,1ZM6,21.25A3.25,3.25,0,1,1,9.25,18,3.25,3.25,0,0,1,6,21.25Z" android:strokeColor="#FFFFFF" android:strokeWidth="0.4" android:strokeMiterLimit="10"/> + <path android:fillColor="#FFFFFF" android:pathData="M18.91,18.7a0.48,0.48,0,0,1-0.48-0.48V13l-2.36,2.36-0.67-0.67,2.84-2.84L15.4,9l0.67-0.67,2.36,2.36V5.52a0.48,0.48,0,0,1,0.81-0.34l3.18,3.18a0.48,0.48,0,0,1,0,0.67h0l-2.84,2.84,2.84,2.84a0.48,0.48,0,0,1,0,0.67h0l-3.18,3.18A0.47,0.47,0,0,1,18.91,18.7ZM19.38,13v4.05l2-2Zm0-6.35v4.05l2-2Z" android:strokeColor="#FFFFFF" android:strokeWidth="0.4" android:strokeMiterLimit="10"/> +</vector> diff --git a/OosPanel/res/drawable-night/ic_volume_media_bt_mute.xml b/OosPanel/res/drawable-night/ic_volume_media_bt_mute.xml new file mode 100644 index 0000000..f333cd7 --- /dev/null +++ b/OosPanel/res/drawable-night/ic_volume_media_bt_mute.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:aapt="http://schemas.android.com/aapt" android:height="@dimen/op_volume_dialog_icon_size" android:width="@dimen/op_volume_dialog_icon_size" android:viewportWidth="24" android:viewportHeight="24"> + <path android:fillColor="#FFFFFF" android:pathData="M18.91,18.7a0.48,0.48,0,0,1-0.48-0.48V13l-2.36,2.36-0.67-0.67,2.84-2.84L15.4,9l0.67-0.67,2.36,2.36V5.52a0.48,0.48,0,0,1,0.81-0.34l3.18,3.18a0.48,0.48,0,0,1,0,0.67h0l-2.84,2.84,2.84,2.84a0.48,0.48,0,0,1,0,0.67h0l-3.18,3.18A0.47,0.47,0,0,1,18.91,18.7ZM19.38,13v4l2-2Zm0-6.35V10.7l2-2Z" android:strokeColor="#FFFFFF" android:strokeWidth="0.4" android:strokeMiterLimit="10"/> + <path android:fillColor="#FFFFFF" android:pathData="M6.7,10.77l12,12,1.06-1.06-12-12L6.71,8.66,2.33,4.28,1.27,5.34,5.64,9.71Z" android:strokeColor="#FFFFFF" android:strokeWidth="0.4" android:strokeMiterLimit="10"/> + <path android:fillColor="#FFFFFF" android:pathData="M9.25,9.09l1.5,1.5V3.83A9.79,9.79,0,0,0,17,6.75V5.25c-2.81,0-6.25-2.85-6.25-4.25H9.25V9.09h0Z" android:strokeColor="#FFFFFF" android:strokeWidth="0.4" android:strokeMiterLimit="10"/> + <path android:fillColor="#FFFFFF" android:pathData="M9.25,11.21v3.34A4.74,4.74,0,1,0,10.75,18V12.71ZM6,21.25A3.25,3.25,0,1,1,9.25,18,3.25,3.25,0,0,1,6,21.25Z" android:strokeColor="#FFFFFF" android:strokeWidth="0.4" android:strokeMiterLimit="10"/> +</vector> diff --git a/OosPanel/res/drawable-night/ic_volume_media_mute.xml b/OosPanel/res/drawable-night/ic_volume_media_mute.xml new file mode 100644 index 0000000..8db7c03 --- /dev/null +++ b/OosPanel/res/drawable-night/ic_volume_media_mute.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:aapt="http://schemas.android.com/aapt" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"> + <path android:fillColor="#FFFFFF" android:pathData="M2.637,1.4131L1.363,2.6871L12.1,13.423V14.286C11.2311,13.5569 10.1343,13.1549 9,13.15C8.0309,13.15 7.0835,13.4374 6.2777,13.9758C5.4719,14.5143 4.8439,15.2795 4.473,16.1749C4.1022,17.0703 4.0051,18.0555 4.1942,19.006C4.3833,19.9565 4.8499,20.8296 5.5352,21.5149C6.2205,22.2001 7.0936,22.6668 8.0441,22.8559C8.9946,23.045 9.9798,22.9479 10.8752,22.5771C11.7705,22.2062 12.5358,21.5781 13.0742,20.7723C13.6127,19.9665 13.9,19.0192 13.9,18.05V15.224L21.363,22.687L22.636,21.414L2.637,1.4131ZM9,21.15C8.3869,21.15 7.7876,20.9682 7.2778,20.6276C6.768,20.287 6.3706,19.8028 6.136,19.2364C5.9014,18.6699 5.84,18.0466 5.9596,17.4453C6.0792,16.8439 6.3745,16.2916 6.808,15.858C7.2415,15.4245 7.7939,15.1292 8.3953,15.0096C8.9966,14.89 9.6199,14.9514 10.1864,15.186C10.7528,15.4207 11.237,15.818 11.5776,16.3278C11.9182,16.8376 12.1,17.4369 12.1,18.05C12.1,18.8722 11.7734,19.6607 11.1921,20.2421C10.6107,20.8234 9.8222,21.15 9,21.15ZM12.1,8.3301V1.0501H13.9C13.9,3.321 17.237,5.1501 20,5.1501V6.95C17.7673,6.9106 15.615,6.1093 13.9,4.679V10.131L12.1,8.3301Z"/> +</vector> diff --git a/OosPanel/res/drawable-night/ic_volume_ringer_mute.xml b/OosPanel/res/drawable-night/ic_volume_ringer_mute.xml new file mode 100644 index 0000000..683f051 --- /dev/null +++ b/OosPanel/res/drawable-night/ic_volume_ringer_mute.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:aapt="http://schemas.android.com/aapt" android:height="@dimen/op_volume_dialog_icon_size" android:width="@dimen/op_volume_dialog_icon_size" android:viewportWidth="24" android:viewportHeight="24"> + <path android:fillColor="#FFFFFF" android:pathData="M2.6367,1.1816L1.3633,2.4551L5.5057,6.5974C5.2348,7.3432 5.0955,8.1304 5.0938,8.9238V12.2315C5.0776,12.7491 4.9159,13.2517 4.6273,13.6818C4.3387,14.1119 3.9348,14.4519 3.4619,14.6631C3.1769,14.8104 2.9381,15.0337 2.772,15.3082C2.6058,15.5828 2.5188,15.8979 2.5205,16.2188V16.5215C2.5212,16.9875 2.7066,17.4342 3.0361,17.7637C3.3656,18.0932 3.8123,18.2786 4.2783,18.2793H8.1561C8.1194,18.4902 8.1005,18.7039 8.0996,18.918C8.0996,19.9524 8.5105,20.9445 9.242,21.676C9.9735,22.4074 10.9656,22.8184 12,22.8184C13.0344,22.8184 14.0265,22.4074 14.758,21.676C15.4895,20.9445 15.9004,19.9524 15.9004,18.918C15.8995,18.7039 15.8806,18.4902 15.8439,18.2793H17.1875L21.3633,22.4551L22.6363,21.1821L2.6367,1.1816ZM12,21.0176C11.4433,21.0171 10.9095,20.7958 10.5159,20.4021C10.1222,20.0084 9.9009,19.4747 9.9004,18.918C9.8993,18.7004 9.9362,18.4843 10.0093,18.2793H13.9907C14.0638,18.4843 14.1007,18.7004 14.0996,18.918C14.0991,19.4747 13.8778,20.0084 13.4841,20.4021C13.0905,20.7958 12.5567,21.0171 12,21.0176ZM4.3213,16.5215L4.2861,16.2627C5.0531,15.9003 5.7037,15.3309 6.1645,14.6186C6.6254,13.9064 6.8782,13.0796 6.8945,12.2315V8.9238C6.8991,8.6381 6.9279,8.3532 6.9806,8.0724L15.3988,16.4906L4.3213,16.5215ZM7.6131,3.6114C8.6202,2.7731 9.8455,2.2395 11.1452,2.0733C12.4449,1.907 13.7651,2.1149 14.9508,2.6727C16.1365,3.2305 17.1384,4.1149 17.839,5.2221C18.5397,6.3294 18.9099,7.6136 18.9063,8.9239V12.2315C18.9224,12.7491 19.0841,13.2518 19.3727,13.6818C19.6613,14.1119 20.0652,14.452 20.5381,14.6631C20.8231,14.8105 21.0619,15.0338 21.228,15.3083C21.3942,15.5828 21.4812,15.8979 21.4795,16.2188V16.5215C21.4778,16.7894 21.4141,17.0532 21.2933,17.2923L17.2264,13.2251C17.148,12.8997 17.1074,12.5662 17.1055,12.2315V8.9238C17.104,7.5702 16.5657,6.2725 15.6085,5.3153C14.6514,4.3582 13.3536,3.8198 12,3.8184C10.8737,3.8187 9.78,4.1969 8.894,4.8924L7.6131,3.6114Z"/> +</vector> diff --git a/OosPanel/res/drawable-night/ic_volume_ringer_vibrate.xml b/OosPanel/res/drawable-night/ic_volume_ringer_vibrate.xml new file mode 100644 index 0000000..3aae335 --- /dev/null +++ b/OosPanel/res/drawable-night/ic_volume_ringer_vibrate.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:aapt="http://schemas.android.com/aapt" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"> + <path android:fillColor="#FFFFFF" android:pathData="M7,2.9001C6.9735,2.9001 6.948,2.9106 6.9293,2.9294C6.9105,2.9481 6.9,2.9736 6.9,3.0001V21.1001H17C17.0265,21.1001 17.0519,21.0896 17.0707,21.0708C17.0894,21.0521 17.1,21.0266 17.1,21.0001V3.0001C17.1,2.9736 17.0894,2.9481 17.0707,2.9294C17.0519,2.9106 17.0265,2.9001 17,2.9001H7ZM5.6565,1.6566C6.0128,1.3003 6.4961,1.1001 7,1.1001H17C17.5039,1.1001 17.9872,1.3003 18.3435,1.6566C18.6998,2.0129 18.9,2.4962 18.9,3.0001V21.0001C18.9,21.504 18.6998,21.9873 18.3435,22.3436C17.9872,22.6999 17.5039,22.9001 17,22.9001H5.1V3.0001C5.1,2.4962 5.3001,2.0129 5.6565,1.6566Z" android:fillType="evenOdd"/> + <path android:fillColor="#FFFFFF" android:pathData="M1.727,5.7286L3.727,8.4696C3.9663,8.7976 3.9564,9.2453 3.7028,9.5623L2.1525,11.5001L3.7028,13.4379C3.9403,13.7348 3.9656,14.1491 3.7659,14.4727L1.7659,17.7137L0.2341,16.7685L1.901,14.0671L0.2972,12.0623C0.0342,11.7336 0.0342,11.2666 0.2972,10.9379L1.8675,8.975L0.2729,6.7896L1.727,5.7286Z" android:fillType="evenOdd"/> + <path android:fillColor="#FFFFFF" android:pathData="M20.2341,9.0275L22.2341,5.7865L23.7659,6.7317L22.0989,9.4331L23.7028,11.4379C23.9657,11.7666 23.9657,12.2336 23.7028,12.5623L22.1324,14.5252L23.727,16.7106L22.2729,17.7716L20.2729,15.0306C20.0336,14.7026 20.0435,14.2549 20.2972,13.9379L21.8474,12.0001L20.2972,10.0623C20.0596,9.7654 20.0343,9.3511 20.2341,9.0275Z" android:fillType="evenOdd"/> +</vector> diff --git a/OosPanel/res/drawable-night/ic_volume_setting__opsettings.xml b/OosPanel/res/drawable-night/ic_volume_setting__opsettings.xml new file mode 100644 index 0000000..aacb11b --- /dev/null +++ b/OosPanel/res/drawable-night/ic_volume_setting__opsettings.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:aapt="http://schemas.android.com/aapt" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"> + <group> + <clip-path android:pathData="M0,0h24v24h-24z"/> + <group> + <clip-path android:pathData="M0,24l0,-24l24,-0l0,24z"/> + <path android:fillColor="#FFFFFF" android:pathData="M3.4116,10.0339L3.4116,6.7547L6.6909,6.7547L6.6909,10.0339L3.4116,10.0339ZM1.8878,5.9928C1.8878,5.572 2.2289,5.2309 2.6497,5.2309L7.4528,5.2309C7.8735,5.2309 8.2147,5.572 8.2147,5.9928L8.2147,10.7958C8.2147,11.2166 7.8735,11.5577 7.4528,11.5577L2.6497,11.5577C2.2289,11.5577 1.8878,11.2166 1.8878,10.7958L1.8878,5.9928ZM10.4149,14.5531L10.4149,17.8324L11.1585,17.8324L11.1585,17.8274L12.9507,17.8274L12.9507,17.8324L13.6942,17.8324L13.6942,14.5531L12.9507,14.5531L12.9507,14.5548L11.1585,14.5548L11.1585,14.5531L10.4149,14.5531ZM11.1585,13.0293L9.653,13.0293C9.2322,13.0293 8.8911,13.3705 8.8911,13.7912L8.8911,18.5943C8.8911,19.0151 9.2322,19.3562 9.653,19.3562L11.1585,19.3562L11.1585,22.99L12.9507,22.99L12.9507,19.3562L14.4561,19.3562C14.8768,19.3562 15.218,19.0151 15.218,18.5943L15.218,13.7912C15.218,13.3705 14.8768,13.0293 14.4561,13.0293L12.9507,13.0293L12.9507,1.034L11.1585,1.034L11.1585,13.0293ZM17.4182,6.7547L17.4182,10.0339L18.1618,10.0339L18.1618,10.0297L19.954,10.0297L19.954,10.0339L20.6975,10.0339L20.6975,6.7547L17.4182,6.7547ZM16.6563,11.5577L18.1618,11.5577L18.1618,22.99L19.954,22.99L19.954,11.5577L21.4594,11.5577C21.8802,11.5577 22.2213,11.2166 22.2213,10.7958L22.2213,5.9928C22.2213,5.572 21.8802,5.2309 21.4594,5.2309L19.954,5.2309L19.954,1.034L18.1618,1.034L18.1618,5.2309L16.6563,5.2309C16.2355,5.2309 15.8944,5.572 15.8944,5.9928L15.8944,10.7958C15.8944,11.2166 16.2355,11.5577 16.6563,11.5577Z" android:fillType="evenOdd"/> + <path android:fillColor="#FFFFFF" android:pathData="M4.1551,10.0304L4.1551,22.99L5.9474,22.99L5.9474,10.0304L4.1551,10.0304ZM5.9474,6.7538L5.9474,1.034L4.1551,1.034L4.1551,6.7538L5.9474,6.7538Z" android:fillType="evenOdd"/> + </group> + </group> +</vector> diff --git a/OosPanel/res/drawable-night/rounded_bg_bottom_background.xml b/OosPanel/res/drawable-night/rounded_bg_bottom_background.xml new file mode 100644 index 0000000..c519a74 --- /dev/null +++ b/OosPanel/res/drawable-night/rounded_bg_bottom_background.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="#121212" /> + <corners + android:bottomLeftRadius="?android:attr/dialogCornerRadius" + android:topLeftRadius="0dp" + android:bottomRightRadius="?android:attr/dialogCornerRadius" + android:topRightRadius="0dp" + /> +</shape> diff --git a/OosPanel/res/drawable-night/vol_seekbar.xml b/OosPanel/res/drawable-night/vol_seekbar.xml new file mode 100644 index 0000000..b943727 --- /dev/null +++ b/OosPanel/res/drawable-night/vol_seekbar.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@android:id/background" android:gravity="center" > + <shape android:shape="rectangle"> + <size android:height="4dp"/> + <solid android:color="#25FFFFFF"/> + <corners android:radius="10dp"/> + </shape> + </item> + <item android:id="@android:id/progress" android:gravity="center"> + <clip android:clipOrientation="horizontal" android:gravity="left"> + <shape android:shape="rectangle"> + <size android:height="4dp"/> + <stroke android:color="?android:attr/colorAccent" android:width="1dp" /> + <solid android:color="?android:attr/colorAccent"/> + <corners android:radius="10dp"/> + </shape> + </clip> + </item> +</layer-list>
\ No newline at end of file diff --git a/OosPanel/res/drawable/btn_volume_media_icon_bg_light.xml b/OosPanel/res/drawable/btn_volume_media_icon_bg_light.xml new file mode 100644 index 0000000..02b428b --- /dev/null +++ b/OosPanel/res/drawable/btn_volume_media_icon_bg_light.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:aapt="http://schemas.android.com/aapt" android:shape="rectangle"> + <corners android:radius="23dp"/> + <solid android:color="@color/nez_contorl_bg_color_cardview_light"/> +</shape> diff --git a/OosPanel/res/drawable/circleboi.xml b/OosPanel/res/drawable/circleboi.xml new file mode 100644 index 0000000..ef296ff --- /dev/null +++ b/OosPanel/res/drawable/circleboi.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> + +<shape + xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="oval"> + <solid + android:color="?android:attr/panelColorBackground"/> + + <size + android:width="41dp" + android:height="41dp"/> + +</shape>
\ No newline at end of file diff --git a/OosPanel/res/drawable/ic_bluetooth_audio.xml b/OosPanel/res/drawable/ic_bluetooth_audio.xml new file mode 100644 index 0000000..3a2ac01 --- /dev/null +++ b/OosPanel/res/drawable/ic_bluetooth_audio.xml @@ -0,0 +1,22 @@ +<!-- + Copyright (C) 2020 The Android Open Source Project + Copyright (C) 2020 The Potato Open Sauce 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="20.0dp" + android:width="20.0dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M12.88,16.29L11,18.17V14.41M11,5.83L12.88,7.71L11,9.58M15.71,7.71L10,2H9V9.58L4.41,5L3,6.41L8.59,12L3,17.58L4.41,19L9,14.41V22H10L15.71,16.29L11.41,12M19.53,6.71L18.26,8C18.89,9.18 19.25,10.55 19.25,12C19.25,13.45 18.89,14.82 18.26,16L19.46,17.22C20.43,15.68 21,13.87 21,11.91C21,10 20.46,8.23 19.53,6.71M14.24,12L16.56,14.33C16.84,13.6 17,12.82 17,12C17,11.18 16.84,10.4 16.57,9.68L14.24,12Z" /> +</vector> diff --git a/OosPanel/res/drawable/ic_volume_empty.xml b/OosPanel/res/drawable/ic_volume_empty.xml new file mode 100644 index 0000000..697c11b --- /dev/null +++ b/OosPanel/res/drawable/ic_volume_empty.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:aapt="http://schemas.android.com/aapt" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"> + <path android:pathData="M 0 0 L 24 0 L 24 24 L 0 24 Z" android:strokeWidth="1" android:fillType="evenOdd"/> + <path android:fillColor="#000000" android:pathData="M5.167,13.25 L5.167,10.6015817 L3.40138782,13.25 L5.167,13.25 Z M6.667,13.25 L8,13.25 C8.41421356,13.25 8.75,13.5857864 8.75,14 C8.75,15.7949254 10.2050746,17.25 12,17.25 C13.7949254,17.25 15.25,15.7949254 15.25,14 C15.25,13.5857864 15.5857864,13.25 16,13.25 L17.25,13.25 L17.25,3.75 L6.667,3.75 L6.667,8.04378413 C6.67253619,8.09549002 6.67268002,8.14810532 6.667,8.20081838 L6.667,13.25 Z M18.75,13.25 L20.5986122,13.25 L18.75,10.4770817 L18.75,13.25 Z M18.75,7.77291827 L22.6183497,13.5754428 C22.7013917,13.696159 22.75,13.842403 22.75,14 L22.75,22 C22.75,22.4142136 22.4142136,22.75 22,22.75 L2,22.75 C1.58578644,22.75 1.25,22.4142136 1.25,22 L1.25,14 C1.25,13.842403 1.29860831,13.696159 1.38165033,13.5754428 L5.167,7.89741827 L5.167,3 C5.167,2.58578644 5.50278644,2.25 5.917,2.25 L18,2.25 C18.4142136,2.25 18.75,2.58578644 18.75,3 L18.75,7.77291827 Z M12,18.75 C9.63184817,18.75 7.6684627,17.0169892 7.30887587,14.75 L2.75,14.75 L2.75,21.25 L21.25,21.25 L21.25,14.75 L16.6911241,14.75 C16.3315373,17.0169892 14.3681518,18.75 12,18.75 Z M9,7.75 L9,6.25 L15,6.25 L15,7.75 L9,7.75 Z M9,10.75 L9,9.25 L14,9.25 L14,10.75 L9,10.75 Z" android:strokeWidth="1"/> +</vector> diff --git a/OosPanel/res/drawable/ic_volume_remote.xml b/OosPanel/res/drawable/ic_volume_remote.xml new file mode 100644 index 0000000..0e5a785 --- /dev/null +++ b/OosPanel/res/drawable/ic_volume_remote.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:aapt="http://schemas.android.com/aapt" android:tint="?android:attr/colorControlNormal" android:height="24dp" android:width="24dp" android:viewportWidth="48" android:viewportHeight="48"> + <path android:fillColor="#ffffff" 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> diff --git a/OosPanel/res/drawable/ic_volume_remote_mute.xml b/OosPanel/res/drawable/ic_volume_remote_mute.xml new file mode 100644 index 0000000..bd883b6 --- /dev/null +++ b/OosPanel/res/drawable/ic_volume_remote_mute.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:aapt="http://schemas.android.com/aapt" android:tint="?android:attr/colorControlNormal" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"> + <path android:fillColor="#ffffff" 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="#ffffff" 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="#ffffff" 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="#ffffff" 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="#ffffff" 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> diff --git a/OosPanel/res/drawable/ic_volume_setting__opsettings.xml b/OosPanel/res/drawable/ic_volume_setting__opsettings.xml new file mode 100644 index 0000000..67fd829 --- /dev/null +++ b/OosPanel/res/drawable/ic_volume_setting__opsettings.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:aapt="http://schemas.android.com/aapt" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"> + <group> + <clip-path android:pathData="M0,0h24v24h-24z"/> + <group> + <clip-path android:pathData="M0,24l0,-24l24,-0l0,24z"/> + <path android:fillColor="#000000" android:pathData="M3.4116,10.0339L3.4116,6.7547L6.6909,6.7547L6.6909,10.0339L3.4116,10.0339ZM1.8878,5.9928C1.8878,5.572 2.2289,5.2309 2.6497,5.2309L7.4528,5.2309C7.8735,5.2309 8.2147,5.572 8.2147,5.9928L8.2147,10.7958C8.2147,11.2166 7.8735,11.5577 7.4528,11.5577L2.6497,11.5577C2.2289,11.5577 1.8878,11.2166 1.8878,10.7958L1.8878,5.9928ZM10.4149,14.5531L10.4149,17.8324L11.1585,17.8324L11.1585,17.8274L12.9507,17.8274L12.9507,17.8324L13.6942,17.8324L13.6942,14.5531L12.9507,14.5531L12.9507,14.5548L11.1585,14.5548L11.1585,14.5531L10.4149,14.5531ZM11.1585,13.0293L9.653,13.0293C9.2322,13.0293 8.8911,13.3705 8.8911,13.7912L8.8911,18.5943C8.8911,19.0151 9.2322,19.3562 9.653,19.3562L11.1585,19.3562L11.1585,22.99L12.9507,22.99L12.9507,19.3562L14.4561,19.3562C14.8768,19.3562 15.218,19.0151 15.218,18.5943L15.218,13.7912C15.218,13.3705 14.8768,13.0293 14.4561,13.0293L12.9507,13.0293L12.9507,1.034L11.1585,1.034L11.1585,13.0293ZM17.4182,6.7547L17.4182,10.0339L18.1618,10.0339L18.1618,10.0297L19.954,10.0297L19.954,10.0339L20.6975,10.0339L20.6975,6.7547L17.4182,6.7547ZM16.6563,11.5577L18.1618,11.5577L18.1618,22.99L19.954,22.99L19.954,11.5577L21.4594,11.5577C21.8802,11.5577 22.2213,11.2166 22.2213,10.7958L22.2213,5.9928C22.2213,5.572 21.8802,5.2309 21.4594,5.2309L19.954,5.2309L19.954,1.034L18.1618,1.034L18.1618,5.2309L16.6563,5.2309C16.2355,5.2309 15.8944,5.572 15.8944,5.9928L15.8944,10.7958C15.8944,11.2166 16.2355,11.5577 16.6563,11.5577Z" android:fillType="evenOdd"/> + <path android:fillColor="#000000" android:pathData="M4.1551,10.0304L4.1551,22.99L5.9474,22.99L5.9474,10.0304L4.1551,10.0304ZM5.9474,6.7538L5.9474,1.034L4.1551,1.034L4.1551,6.7538L5.9474,6.7538Z" android:fillType="evenOdd"/> + </group> + </group> +</vector> diff --git a/OosPanel/res/drawable/ic_volume_setting_expand.xml b/OosPanel/res/drawable/ic_volume_setting_expand.xml new file mode 100644 index 0000000..67fd829 --- /dev/null +++ b/OosPanel/res/drawable/ic_volume_setting_expand.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:aapt="http://schemas.android.com/aapt" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"> + <group> + <clip-path android:pathData="M0,0h24v24h-24z"/> + <group> + <clip-path android:pathData="M0,24l0,-24l24,-0l0,24z"/> + <path android:fillColor="#000000" android:pathData="M3.4116,10.0339L3.4116,6.7547L6.6909,6.7547L6.6909,10.0339L3.4116,10.0339ZM1.8878,5.9928C1.8878,5.572 2.2289,5.2309 2.6497,5.2309L7.4528,5.2309C7.8735,5.2309 8.2147,5.572 8.2147,5.9928L8.2147,10.7958C8.2147,11.2166 7.8735,11.5577 7.4528,11.5577L2.6497,11.5577C2.2289,11.5577 1.8878,11.2166 1.8878,10.7958L1.8878,5.9928ZM10.4149,14.5531L10.4149,17.8324L11.1585,17.8324L11.1585,17.8274L12.9507,17.8274L12.9507,17.8324L13.6942,17.8324L13.6942,14.5531L12.9507,14.5531L12.9507,14.5548L11.1585,14.5548L11.1585,14.5531L10.4149,14.5531ZM11.1585,13.0293L9.653,13.0293C9.2322,13.0293 8.8911,13.3705 8.8911,13.7912L8.8911,18.5943C8.8911,19.0151 9.2322,19.3562 9.653,19.3562L11.1585,19.3562L11.1585,22.99L12.9507,22.99L12.9507,19.3562L14.4561,19.3562C14.8768,19.3562 15.218,19.0151 15.218,18.5943L15.218,13.7912C15.218,13.3705 14.8768,13.0293 14.4561,13.0293L12.9507,13.0293L12.9507,1.034L11.1585,1.034L11.1585,13.0293ZM17.4182,6.7547L17.4182,10.0339L18.1618,10.0339L18.1618,10.0297L19.954,10.0297L19.954,10.0339L20.6975,10.0339L20.6975,6.7547L17.4182,6.7547ZM16.6563,11.5577L18.1618,11.5577L18.1618,22.99L19.954,22.99L19.954,11.5577L21.4594,11.5577C21.8802,11.5577 22.2213,11.2166 22.2213,10.7958L22.2213,5.9928C22.2213,5.572 21.8802,5.2309 21.4594,5.2309L19.954,5.2309L19.954,1.034L18.1618,1.034L18.1618,5.2309L16.6563,5.2309C16.2355,5.2309 15.8944,5.572 15.8944,5.9928L15.8944,10.7958C15.8944,11.2166 16.2355,11.5577 16.6563,11.5577Z" android:fillType="evenOdd"/> + <path android:fillColor="#000000" android:pathData="M4.1551,10.0304L4.1551,22.99L5.9474,22.99L5.9474,10.0304L4.1551,10.0304ZM5.9474,6.7538L5.9474,1.034L4.1551,1.034L4.1551,6.7538L5.9474,6.7538Z" android:fillType="evenOdd"/> + </group> + </group> +</vector> diff --git a/OosPanel/res/drawable/rounded_bg_bottom.xml b/OosPanel/res/drawable/rounded_bg_bottom.xml new file mode 100644 index 0000000..90ed636 --- /dev/null +++ b/OosPanel/res/drawable/rounded_bg_bottom.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="?android:attr/colorPrimaryDark" /> + <corners + android:bottomLeftRadius="?android:attr/dialogCornerRadius" + android:topLeftRadius="0dp" + android:bottomRightRadius="?android:attr/dialogCornerRadius" + android:topRightRadius="0dp" + /> +</shape> diff --git a/OosPanel/res/drawable/rounded_bg_top.xml b/OosPanel/res/drawable/rounded_bg_top.xml new file mode 100644 index 0000000..988ab58 --- /dev/null +++ b/OosPanel/res/drawable/rounded_bg_top.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="?android:attr/colorPrimaryDark" /> + <corners + android:topLeftRadius="?android:attr/dialogCornerRadius" + android:topRightRadius="?android:attr/dialogCornerRadius" /> +</shape> diff --git a/OosPanel/res/drawable/rounded_bg_top_circle.xml b/OosPanel/res/drawable/rounded_bg_top_circle.xml new file mode 100644 index 0000000..9354ad0 --- /dev/null +++ b/OosPanel/res/drawable/rounded_bg_top_circle.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2021 NezukoOS + 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. + --> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:drawable="@drawable/rounded_bg_top" /> + + <item + android:drawable="@drawable/circleboi" /> +</layer-list>
\ No newline at end of file diff --git a/OosPanel/res/drawable/vol_seekbar.xml b/OosPanel/res/drawable/vol_seekbar.xml new file mode 100644 index 0000000..6592148 --- /dev/null +++ b/OosPanel/res/drawable/vol_seekbar.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@android:id/background" android:gravity="center" > + <shape android:shape="rectangle"> + <size android:height="4dp"/> + <solid android:color="#25000000"/> + <corners android:radius="10dp"/> + </shape> + </item> + <item android:id="@android:id/progress" android:gravity="center"> + <clip android:clipOrientation="horizontal" android:gravity="left"> + <shape android:shape="rectangle"> + <size android:height="4dp"/> + <stroke android:color="?android:attr/colorAccent" android:width="1dp" /> + <solid android:color="?android:attr/colorAccent"/> + <corners android:radius="10dp"/> + </shape> + </clip> + </item> +</layer-list>
\ No newline at end of file diff --git a/OosPanel/res/drawable/volpprog.xml b/OosPanel/res/drawable/volpprog.xml new file mode 100644 index 0000000..6a47749 --- /dev/null +++ b/OosPanel/res/drawable/volpprog.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <shape android:shape="oval"> + <size android:height="10dp" android:width="10dp"/> + </shape> + </item> +</selector>
\ No newline at end of file diff --git a/OosPanel/res/drawable/volpseek.xml b/OosPanel/res/drawable/volpseek.xml new file mode 100644 index 0000000..90039e1 --- /dev/null +++ b/OosPanel/res/drawable/volpseek.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@android:id/background"> + <shape android:shape="rectangle"> + <solid android:color="@android:color/transparent"/> + <corners android:radius="2dp"/> + </shape> + </item> + <item android:id="@android:id/progress"> + <clip android:clipOrientation="horizontal" android:gravity="left"> + <shape android:shape="rectangle"> + <stroke android:color="?android:attr/colorAccent" android:width="1dp" /> + <solid android:color="?android:attr/colorAccent"/> + <corners android:radius="10dp"/> + </shape> + </clip> + </item> +</layer-list> diff --git a/OosPanel/res/layout/volume_dialog_oos.xml b/OosPanel/res/layout/volume_dialog_oos.xml new file mode 100644 index 0000000..3357087 --- /dev/null +++ b/OosPanel/res/layout/volume_dialog_oos.xml @@ -0,0 +1,188 @@ +<!-- + Copyright (C) 2015 The Android Open Source Project + Copyright (C) 2020 The Potato Open Sauce 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" + xmlns:sysui="http://schemas.android.com/apk/res-auto" + android:id="@+id/volume_dialog_container" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="right" + android:layout_gravity="right" + android:background="@android:color/transparent"> + + <!-- right-aligned to be physically near volume button --> + <LinearLayout + android:id="@+id/volume_dialog" + android:minWidth="@dimen/volume_dialog_panel_width" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@android:color/transparent" + android:paddingRight="@dimen/volume_dialog_panel_transparent_padding_right" + android:paddingTop="@dimen/volume_dialog_panel_transparent_padding" + android:paddingBottom="@dimen/volume_dialog_panel_transparent_padding" + android:paddingLeft="@dimen/volume_dialog_panel_transparent_padding_right" + android:orientation="vertical" + android:clipToPadding="false"> + + <FrameLayout + android:id="@+id/ringer" + android:layout_width="@dimen/volume_dialog_ringer_size" + android:layout_height="@dimen/volume_dialog_ringer_size" + android:translationZ="@dimen/volume_dialog_elevation" + android:clipToPadding="false" + android:background="@drawable/rounded_bg_top"> + + <ImageView + android:id="@+id/background_image_view" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:scaleType="fitCenter" + android:layout_gravity="center" + android:src="@drawable/circleboi"/> + + <co.potatoproject.plugin.volume.common.AlphaOptimizedImageButton + android:id="@+id/ringer_icon" + style="@style/VolumeButtons" + android:background="@android:color/transparent" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:scaleType="fitCenter" + android:padding="@dimen/volume_dialog_ringer_icon_padding" + android:tint="?android:attr/colorAccent" + android:layout_gravity="center" + android:soundEffectsEnabled="false" /> + + <include layout="@layout/volume_dnd_icon" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="6dp"/> + </FrameLayout> + + <LinearLayout + android:id="@+id/main" + android:minWidth="@dimen/volume_dialog_panel_width" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="right" + android:layout_gravity="right" + android:orientation="vertical" + android:translationZ="@dimen/volume_dialog_elevation" + android:clipChildren="false" + android:clipToPadding="false" + android:background="@drawable/rounded_bg_bottom" > + + <TextView + android:textSize="29px" + android:ellipsize="end" + android:gravity="center" + android:layout_gravity="top" + android:id="@+id/volume_row_type" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:visibility="gone" + android:maxLines="1" + style="@style/nez_contorl_text_style_descriptions"/> + <LinearLayout + android:id="@+id/volume_dialog_rows" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minWidth="@dimen/volume_dialog_panel_width" + android:gravity="center" + android:orientation="horizontal" + android:paddingRight="@dimen/volume_dialog_stream_padding" + android:paddingLeft="@dimen/volume_dialog_stream_padding" + android:animateLayoutChanges="true"> + <!-- volume rows added and removed here! :-) --> + </LinearLayout> + <FrameLayout + android:id="@+id/expandable_indicator_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:animateLayoutChanges="true" + android:background="@drawable/rounded_bg_bottom_background"> + <co.potatoproject.plugin.volume.common.AlphaOptimizedImageButton + android:id="@+id/media_output" + android:src="@drawable/ic_bluetooth_audio" + android:layout_width="@dimen/volume_dialog_tap_target_size" + android:layout_height="@dimen/volume_dialog_tap_target_size" + android:visibility="gone" + android:layout_marginLeft="8dp" + android:layout_marginRight="8dp" + android:contentDescription="@string/accessibility_volume_settings" + android:background="@drawable/ripple_drawable_20dp" + android:tint="?android:attr/textColorSecondary" + android:animateLayoutChanges="true" + android:soundEffectsEnabled="false" /> + + <View + android:id="@+id/dummy_button" + android:layout_height="1dp" + android:layout_width="1dp" /> + + <co.potatoproject.plugin.volume.common.ExpandableIndicator + android:id="@+id/expandable_indicator" + android:src="@drawable/ic_volume_setting__opsettings" + android:layout_width="@dimen/volume_dialog_tap_target_size" + android:layout_height="@dimen/volume_dialog_tap_target_size" + android:clipToPadding="false" + android:clickable="true" + android:focusable="true" + android:layout_marginLeft="8dp" + android:layout_marginRight="8dp" + android:contentDescription="@string/accessibility_quick_settings_expand" + android:background="@drawable/ripple_drawable_20dp" + android:tint="?android:attr/textColorSecondary" + android:soundEffectsEnabled="false" + android:padding="16dp" + android:rotation="90" /> + </FrameLayout> + </LinearLayout> + + <FrameLayout + android:id="@+id/odi_captions" + android:layout_width="@dimen/volume_dialog_caption_size" + android:layout_height="@dimen/volume_dialog_caption_size" + android:layout_marginTop="@dimen/volume_dialog_spacer" + android:gravity="right" + android:layout_gravity="right" + android:clipToPadding="false" + android:translationZ="@dimen/volume_dialog_elevation" + android:background="@drawable/rounded_bg_full"> + <co.potatoproject.plugin.volume.common.CaptionsToggleImageButton + android:id="@+id/odi_captions_icon" + style="@style/VolumeButtons" + android:background="@drawable/rounded_ripple" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:tint="@color/caption_tint_color_selector" + android:layout_gravity="center" + android:soundEffectsEnabled="false" + sysui:optedOut="false"/> + </FrameLayout> + + </LinearLayout> + + <ViewStub + android:id="@+id/odi_captions_tooltip_stub" + android:inflatedId="@+id/odi_captions_tooltip_view" + android:layout="@layout/volume_tool_tip_view" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginRight="@dimen/volume_tool_tip_right_margin" + android:layout_marginBottom="@dimen/volume_tool_tip_bottom_margin"/> + +</FrameLayout> diff --git a/OosPanel/res/layout/volume_dialog_oos_row.xml b/OosPanel/res/layout/volume_dialog_oos_row.xml new file mode 100644 index 0000000..ce0e129 --- /dev/null +++ b/OosPanel/res/layout/volume_dialog_oos_row.xml @@ -0,0 +1,84 @@ +<!-- + Copyright (C) 2015 The Android Open Source Project + Copyright (C) 2020 The Potato Open Sauce 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:tag="row" + android:layout_height="wrap_content" + android:layout_width="@dimen/volume_dialog_panel_width" + android:clipChildren="false" + android:clipToPadding="false"> + + <LinearLayout + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:gravity="center" + android:layout_gravity="center" + android:orientation="vertical" > + <TextView + android:id="@+id/volume_row_header" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ellipsize="end" + android:maxLength="10" + android:maxLines="1" + android:visibility="gone" + android:textColor="?android:attr/colorControlNormal" + android:textAppearance="@style/TextAppearance.Volume.Header" /> + <FrameLayout + android:id="@+id/volume_row_slider_frame" + android:layout_width="match_parent" + android:layout_marginTop="@dimen/volume_dialog_slider_margin_top" + android:layout_marginBottom="@dimen/volume_dialog_slider_margin_bottom" + android:layoutDirection="rtl" + android:layout_height="@dimen/volume_dialog_slider_height"> + <SeekBar + android:id="@+id/volume_row_slider" + android:clickable="true" + android:layout_width="@dimen/volume_dialog_slider_height" + android:layout_height="match_parent" + android:progressDrawable="@drawable/vol_seekbar" + android:layoutDirection="rtl" + android:layout_gravity="center" + android:rotation="-90" /> + </FrameLayout> + + <co.potatoproject.plugin.volume.common.AlphaOptimizedImageButton + android:id="@+id/volume_row_icon" + style="@style/VolumeButtons" + android:visibility="gone" + android:layout_width="@dimen/volume_dialog_tap_target_size" + android:layout_height="@dimen/volume_dialog_tap_target_size" + android:background="@drawable/ripple_drawable_20dp" + android:layout_marginBottom="@dimen/volume_dialog_row_margin_bottom" + android:soundEffectsEnabled="false" /> + + <co.potatoproject.plugin.volume.common.AlphaOptimizedImageButton + android:id="@+id/volume_row_app_icon" + style="@style/VolumeButtons" + android:visibility="gone" + android:layout_width="@dimen/volume_dialog_tap_target_app_size" + android:layout_height="@dimen/volume_dialog_tap_target_app_size" + android:background="@drawable/ripple_drawable_20dp" + android:layout_marginBottom="@dimen/volume_dialog_row_margin_bottom" + android:padding="@dimen/volume_row_app_icon_padding" + android:soundEffectsEnabled="false" + android:scaleType="centerInside" /> + </LinearLayout> + + <include layout="@layout/volume_dnd_icon"/> + +</FrameLayout> diff --git a/OosPanel/res/values/colors.xml b/OosPanel/res/values/colors.xml new file mode 100644 index 0000000..4ac002f --- /dev/null +++ b/OosPanel/res/values/colors.xml @@ -0,0 +1,4 @@ +<resources> + + <color name="nez_contorl_bg_color_cardview_light">#ffffff</color> +</resources> diff --git a/OosPanel/res/values/dimens.xml b/OosPanel/res/values/dimens.xml new file mode 100644 index 0000000..b9ae8af --- /dev/null +++ b/OosPanel/res/values/dimens.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 The Potato Open Sauce 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> + <dimen name="volume_dialog_row_margin_bottom">8dp</dimen> + <dimen name="volume_row_app_icon_padding">8dp</dimen> + <dimen name="volume_dialog_tap_target_app_size">43dp</dimen> + <dimen name="volume_dialog_slider_margin_top">12dp</dimen> + <dimen name="volume_dialog_slider_height">130dp</dimen> + <dimen name="op_volume_dialog_icon_size">62px</dimen> +</resources> diff --git a/OosPanel/res/values/strings.xml b/OosPanel/res/values/strings.xml new file mode 100644 index 0000000..cca0273 --- /dev/null +++ b/OosPanel/res/values/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 The Potato Open Sauce 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> + <string name="plugin_label">Oos panel</string> + <string name="volume_ringer_hint_mute">Mute</string> + <string name="volume_ringer_hint_vibrate">Vibrate</string> + <string name="volume_ringer_hint_muted">Muted</string> + <string name="volume_ringer_hint_unmuted">Unmuted</string> + <string name="volume_ringer_hint_vibrating">Vibrate</string> +</resources> diff --git a/OosPanel/res/values/styles.xml b/OosPanel/res/values/styles.xml new file mode 100644 index 0000000..96bd1df --- /dev/null +++ b/OosPanel/res/values/styles.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <style name="nez_contorl_text_style_descriptions"> + <item name="android:textSize">11.3sp</item> + <item name="android:lineSpacingMultiplier">1.04</item> + </style> + +</resources> diff --git a/OosPanel/src/co/potatoproject/plugin/volume/oos/VolumeDialogImpl.java b/OosPanel/src/co/potatoproject/plugin/volume/oos/VolumeDialogImpl.java new file mode 100644 index 0000000..ed53be2 --- /dev/null +++ b/OosPanel/src/co/potatoproject/plugin/volume/oos/VolumeDialogImpl.java @@ -0,0 +1,1737 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * Copyright (C) 2020 The Potato Open Sauce 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 co.potatoproject.plugin.volume.oos; + +import android.media.AppTrackData; +import android.database.ContentObserver; +import android.os.UserHandle; +import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; +import static android.media.AudioManager.RINGER_MODE_NORMAL; +import static android.media.AudioManager.RINGER_MODE_SILENT; +import static android.media.AudioManager.RINGER_MODE_VIBRATE; +import static android.media.AudioManager.STREAM_ACCESSIBILITY; +import static android.media.AudioManager.STREAM_ALARM; +import static android.media.AudioManager.STREAM_MUSIC; +import static android.media.AudioManager.STREAM_RING; +import static android.media.AudioManager.STREAM_VOICE_CALL; +import static android.view.View.ACCESSIBILITY_LIVE_REGION_POLITE; +import static android.view.View.GONE; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; + +import static co.potatoproject.plugin.volume.common.Events.DISMISS_REASON_SETTINGS_CLICKED; + +import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; +import android.app.ActivityManager; +import android.app.Dialog; +import android.app.KeyguardManager; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothProfile; +import android.content.ContentResolver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.res.ColorStateList; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.Region; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.media.AudioManager; +import android.media.AudioSystem; +import android.media.AppTrackData; +import android.os.Debug; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.SystemClock; +import android.os.VibrationEffect; +import android.provider.Settings; +import android.provider.Settings.Global; +import android.text.InputFilter; +import android.util.Log; +import android.util.Slog; +import android.util.SparseBooleanArray; +import android.view.ContextThemeWrapper; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.AccessibilityDelegate; +import android.view.ViewGroup; +import android.view.ViewPropertyAnimator; +import android.view.ViewStub; +import android.view.ViewTreeObserver; +import android.view.ViewTreeObserver.InternalInsetsInfo; +import android.view.ViewTreeObserver.OnComputeInternalInsetsListener; +import android.view.Window; +import android.view.WindowManager; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.AccessibilityNodeInfo; +import android.view.animation.DecelerateInterpolator; +import android.widget.FrameLayout; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.SeekBar; +import android.widget.SeekBar.OnSeekBarChangeListener; +import android.widget.TextView; +import android.widget.Toast; + +import co.potatoproject.plugin.volume.common.*; + +import co.potatoproject.plugin.volume.oos.R; + +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.PluginDependency; +import com.android.systemui.plugins.VolumeDialog; +import com.android.systemui.plugins.VolumeDialogController.State; +import com.android.systemui.plugins.VolumeDialogController.StreamState; +import com.android.systemui.plugins.VolumeDialogController; +import com.android.systemui.plugins.annotations.Requires; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +/** + * Visual presentation of the volume dialog. + * + * A client of VolumeDialogControllerImpl and its state model. + * + * Methods ending in "H" must be called on the (ui) handler. + */ +@Requires(target = VolumeDialog.class, version = VolumeDialog.VERSION) +@Requires(target = VolumeDialog.Callback.class, version = VolumeDialog.Callback.VERSION) +@Requires(target = VolumeDialogController.class, version = VolumeDialogController.VERSION) +@Requires(target = ActivityStarter.class, version = ActivityStarter.VERSION) +public class VolumeDialogImpl implements VolumeDialog { + private static final String TAG = Utils.logTag(VolumeDialogImpl.class); + public static final String ACTION_MEDIA_OUTPUT = + "com.android.settings.panel.action.MEDIA_OUTPUT"; + + private static final long USER_ATTEMPT_GRACE_PERIOD = 1000; + private static final int UPDATE_ANIMATION_DURATION = 80; + + static final int DIALOG_TIMEOUT_MILLIS = 3000; + static final int DIALOG_SAFETYWARNING_TIMEOUT_MILLIS = 5000; + static final int DIALOG_ODI_CAPTIONS_TOOLTIP_TIMEOUT_MILLIS = 5000; + static final int DIALOG_HOVERING_TIMEOUT_MILLIS = 16000; + static final int DIALOG_SHOW_ANIMATION_DURATION = 300; + static final int DIALOG_HIDE_ANIMATION_DURATION = 250; + + private SysUIR mSysUIR; + private Context mContext; + private Context mSysUIContext; + private WindowManager mWindowManager; + private WindowManager.LayoutParams mWindowParams; + private final H mHandler = new H(); + private VolumeDialogController mController; + + private View mDialog; + private LinearLayout mDialogView; + private ViewGroup mDialogRowsView; + private ViewGroup mRinger; + private ImageButton mRingerIcon; + private ViewGroup mODICaptionsView; + private TextView mModeIndicator; + private CaptionsToggleImageButton mODICaptionsIcon; + private View mMediaOutputView; + private ImageButton mMediaOutputIcon; + private View mExpandRowsView; + private ExpandableIndicator mExpandRows; + private FrameLayout mZenIcon; + private final List<VolumeRow> mRows = new ArrayList<>(); + private ConfigurableTexts mConfigurableTexts; + private SparseBooleanArray mDynamic = new SparseBooleanArray(); + private KeyguardManager mKeyguard; + private ActivityManager mActivityManager; + private AccessibilityManager mAccessibilityMgr; + private final Object mSafetyWarningLock = new Object(); + private final Accessibility mAccessibility = new Accessibility(); + private final List<VolumeRow> mAppRows = new ArrayList<>(); + private boolean mShowing; + private boolean mShowA11yStream; + + private int mActiveStream; + private int mPrevActiveStream; + private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE; + private boolean mSilentMode = VolumePrefs.DEFAULT_ENABLE_SILENT_MODE; + private State mState; + private SafetyWarningDialog mSafetyWarning; + private boolean mHovering = false; + private boolean mShowActiveStreamOnly; + private boolean mConfigChanged = false; + private boolean mHasSeenODICaptionsTooltip; + private ViewStub mODICaptionsTooltipViewStub; + private View mODICaptionsTooltipView = null; + + private SettingsObserver settingsObserver; + private boolean mExpanded; + private boolean mLeftVolumeRocker; + private boolean mAppVolume; + + public VolumeDialogImpl() {} + + @Override + public void onCreate(Context sysuiContext, Context pluginContext) { + mSysUIR = new SysUIR(pluginContext); + mContext = pluginContext; + mSysUIContext = + new ContextThemeWrapper(sysuiContext, mSysUIR.style("qs_theme", sysuiContext)); + mController = PluginDependency.get(this, VolumeDialogController.class); + mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); + mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); + mAccessibilityMgr = mContext.getSystemService(AccessibilityManager.class); + mShowActiveStreamOnly = showActiveStreamOnly(); + mHasSeenODICaptionsTooltip = + Prefs.getBoolean(sysuiContext, Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, false); + mLeftVolumeRocker = Settings.System.getInt(mContext.getContentResolver(), Settings.System.VOLUME_PANEL_ON_LEFT, 0) == 1; + settingsObserver = new SettingsObserver(mHandler); + settingsObserver.observe(); + } + + public void init(int windowType, Callback callback) { + initDialog(); + + mAccessibility.init(); + + mController.addCallback(mControllerCallbackH, mHandler); + mController.getState(); + } + + @Override + public void destroy() { + mController.removeCallback(mControllerCallbackH); + mHandler.removeCallbacksAndMessages(null); + settingsObserver.unobserve(); + } + + private void initDialog() { + mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); + + mSysUIContext.getTheme().applyStyle(mSysUIContext.getThemeResId(), true); + mSysUIContext.getTheme().rebase(); + mContext.getTheme().setTo(mSysUIContext.getTheme()); + + mConfigurableTexts = new ConfigurableTexts(mContext); + mHovering = false; + mShowing = false; + mExpanded = false; + mWindowParams = new WindowManager.LayoutParams(); + mWindowParams.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND; + mWindowParams.flags &= ~WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; + mWindowParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; + mWindowParams.type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; + mWindowParams.format = PixelFormat.TRANSLUCENT; + mWindowParams.windowAnimations = -1; + mDialog = LayoutInflater.from(mContext).inflate(R.layout.volume_dialog_oos, + (ViewGroup) null, false); + + mDialog.setOnTouchListener((v, event) -> { + if (mShowing) { + if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { + dismissH(Events.DISMISS_REASON_TOUCH_OUTSIDE); + return true; + } + } + return false; + }); + + mDialogView = mDialog.findViewById(R.id.volume_dialog); + mDialogView.setAlpha(0); + + mDialogView.setOnHoverListener((v, event) -> { + int action = event.getActionMasked(); + mHovering = (action == MotionEvent.ACTION_HOVER_ENTER) + || (action == MotionEvent.ACTION_HOVER_MOVE); + rescheduleTimeoutH(); + return true; + }); + + FrameLayout.LayoutParams dialogViewLP = + (FrameLayout.LayoutParams) mDialogView.getLayoutParams(); + dialogViewLP.gravity = Gravity.CENTER_VERTICAL; + mDialogView.setLayoutParams(dialogViewLP); + + mDialogRowsView = mDialog.findViewById(R.id.volume_dialog_rows); + mModeIndicator = mDialog.findViewById(R.id.volume_row_type); + mRinger = mDialog.findViewById(R.id.ringer); + if (mRinger != null) { + mRingerIcon = mRinger.findViewById(R.id.ringer_icon); + mZenIcon = mRinger.findViewById(R.id.dnd_icon); + } + + mODICaptionsView = mDialog.findViewById(R.id.odi_captions); + if (mODICaptionsView != null) { + mODICaptionsIcon = mODICaptionsView.findViewById(R.id.odi_captions_icon); + mODICaptionsIcon.setImageDrawable( + mSysUIContext.getDrawable(mSysUIR.drawable("ic_volume_odi_captions_disabled"))); + } + mODICaptionsTooltipViewStub = mDialog.findViewById(R.id.odi_captions_tooltip_stub); + if (mHasSeenODICaptionsTooltip && mODICaptionsTooltipViewStub != null) { + mDialogView.removeView(mODICaptionsTooltipViewStub); + mODICaptionsTooltipViewStub = null; + } + + mMediaOutputIcon = mDialog.findViewById(R.id.media_output); + + mExpandRowsView = mDialog.findViewById(R.id.expandable_indicator_container); + mExpandRows = mDialog.findViewById(R.id.expandable_indicator); + + LinearLayout.LayoutParams mainLP = + (LinearLayout.LayoutParams) mDialog.findViewById(R.id.main).getLayoutParams(); + FrameLayout.LayoutParams dummyButtonLP = + (FrameLayout.LayoutParams) mDialog.findViewById(R.id.dummy_button).getLayoutParams(); + LinearLayout.LayoutParams ringerLP = + (LinearLayout.LayoutParams) mRinger.getLayoutParams(); + FrameLayout.LayoutParams mediaOutputLP = + (FrameLayout.LayoutParams) mMediaOutputIcon.getLayoutParams(); + FrameLayout.LayoutParams expandRowsLP = + (FrameLayout.LayoutParams) mExpandRows.getLayoutParams(); + LinearLayout.LayoutParams captionsLP = + (LinearLayout.LayoutParams) mODICaptionsView.getLayoutParams(); + + if(!isAudioPanelOnLeftSide()) { + mainLP.gravity = Gravity.RIGHT; + ringerLP.gravity = Gravity.RIGHT; + mExpandRows.setRotation(90); + dummyButtonLP.gravity = Gravity.LEFT; + mediaOutputLP.gravity = Gravity.LEFT; + expandRowsLP.gravity = Gravity.RIGHT; + captionsLP.gravity = Gravity.RIGHT; + } else { + mainLP.gravity = Gravity.LEFT; + ringerLP.gravity = Gravity.LEFT; + mExpandRows.setRotation(-90); + dummyButtonLP.gravity = Gravity.RIGHT; + mediaOutputLP.gravity = Gravity.RIGHT; + expandRowsLP.gravity = Gravity.LEFT; + captionsLP.gravity = Gravity.LEFT; + } + + mDialog.findViewById(R.id.main).setLayoutParams(mainLP); + mDialog.findViewById(R.id.dummy_button).setLayoutParams(dummyButtonLP); + mRinger.setLayoutParams(ringerLP); + mMediaOutputIcon.setLayoutParams(mediaOutputLP); + mExpandRows.setLayoutParams(expandRowsLP); + mODICaptionsView.setLayoutParams(captionsLP); + + if (mRows.isEmpty()) { + if (!AudioSystem.isSingleVolume(mContext)) { + addRow(STREAM_ACCESSIBILITY, mSysUIR.drawable("ic_volume_accessibility"), + mSysUIR.drawable("ic_volume_accessibility"), true, false); + } + addRow(AudioManager.STREAM_MUSIC, + mSysUIR.drawable("ic_volume_media"), mSysUIR.drawable("ic_volume_media_mute"), true, true); + if (!AudioSystem.isSingleVolume(mContext)) { + addRow(AudioManager.STREAM_RING, + mSysUIR.drawable("ic_volume_ringer"), mSysUIR.drawable("ic_volume_ringer_mute"), true, false); + addRow(STREAM_ALARM, + mSysUIR.drawable("ic_alarm"), mSysUIR.drawable("ic_volume_alarm_mute"), true, false); + addRow(AudioManager.STREAM_VOICE_CALL, + com.android.internal.R.drawable.ic_phone, + com.android.internal.R.drawable.ic_phone, false, false); + addRow(AudioManager.STREAM_BLUETOOTH_SCO, + mSysUIR.drawable("ic_volume_bt_sco"), mSysUIR.drawable("ic_volume_bt_sco"), false, false); + addRow(AudioManager.STREAM_SYSTEM, mSysUIR.drawable("ic_volume_system"), + mSysUIR.drawable("ic_volume_system_mute"), false, false); + } + } else { + addExistingRows(); + } + + updateRowsH(getActiveRow()); + initRingerH(); + initSettingsH(); + initODICaptionsH(); + } + + private class SettingsObserver extends ContentObserver { + SettingsObserver(Handler handler) { + super(handler); + } + + void unobserve() { + mContext.getContentResolver().unregisterContentObserver(this); + } + + void observe() { + mContext.getContentResolver().registerContentObserver(Settings.System.getUriFor(Settings.System.SHOW_APP_VOLUME), false, this, UserHandle.USER_ALL); + update(); + } + + + @Override + public void onChange(boolean selfChange) { + update(); + initDialog(); + } + + + public void update() { + mAppVolume = Settings.System.getIntForUser(mContext.getContentResolver(), Settings.System.SHOW_APP_VOLUME, 0, UserHandle.USER_CURRENT) == 1; + } + + } + private final OnComputeInternalInsetsListener mInsetsListener = internalInsetsInfo -> { + internalInsetsInfo.touchableRegion.setEmpty(); + internalInsetsInfo.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION); + View main = mDialog.findViewById(R.id.main); + int[] mainLocation = new int[2]; + main.getLocationInWindow(mainLocation); + int[] dialogLocation = new int[2]; + mDialogView.getLocationInWindow(dialogLocation); + internalInsetsInfo.touchableRegion.set(new Region( + mainLocation[0] - main.getWidth(), + dialogLocation[1], + mainLocation[0] + main.getWidth(), + dialogLocation[1] + mDialogView.getHeight() + )); + }; + + protected ViewGroup getDialogView() { + return mDialogView; + } + + private int getAlphaAttr(int attr) { + TypedArray ta = mContext.obtainStyledAttributes(new int[]{attr}); + float alpha = ta.getFloat(0, 0); + ta.recycle(); + return (int) (alpha * 255); + } + + private boolean isLandscape() { + return mContext.getResources().getConfiguration().orientation == + Configuration.ORIENTATION_LANDSCAPE; + } + + public void setStreamImportant(int stream, boolean important) { + mHandler.obtainMessage(H.SET_STREAM_IMPORTANT, stream, important ? 1 : 0).sendToTarget(); + } + + public void setAutomute(boolean automute) { + if (mAutomute == automute) return; + mAutomute = automute; + mHandler.sendEmptyMessage(H.RECHECK_ALL); + } + + public void setSilentMode(boolean silentMode) { + if (mSilentMode == silentMode) return; + mSilentMode = silentMode; + mHandler.sendEmptyMessage(H.RECHECK_ALL); + } + + private void addRow(int stream, int iconRes, int iconMuteRes, boolean important, + boolean defaultStream) { + addRow(stream, iconRes, iconMuteRes, important, defaultStream, false); + } + + private void addRow(int stream, int iconRes, int iconMuteRes, boolean important, + boolean defaultStream, boolean dynamic) { + if (D.BUG) Slog.d(TAG, "Adding row for stream " + stream); + VolumeRow row = new VolumeRow(); + initRow(row, stream, iconRes, iconMuteRes, important, defaultStream); + if(!isAudioPanelOnLeftSide()){ + mDialogRowsView.addView(row.view); + } else { + mDialogRowsView.addView(row.view); + } + mRows.add(row); + } + + private void addAppRow(AppTrackData data) { + VolumeRow row = new VolumeRow(); + initAppRow(row, data); + mDialogRowsView.addView(row.view); + mAppRows.add(row); + } + + @SuppressLint("InflateParams") + private void initAppRow(final VolumeRow row, final AppTrackData data) { + row.view = LayoutInflater.from(mContext).inflate(R.layout.volume_dialog_oos_row, null); + + row.packageName = data.getPackageName(); + row.isAppVolumeRow = true; + + row.view.setTag(row); + row.slider = row.view.findViewById(R.id.volume_row_slider); + row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row)); + + row.appMuted = data.isMuted(); + row.slider.setProgress((int) (data.getVolume() * 100)); + + row.dndIcon = row.view.findViewById(R.id.dnd_icon); + row.dndIcon.setVisibility(View.GONE); + + row.icon = row.view.findViewById(R.id.volume_row_app_icon); + row.icon.setVisibility(View.VISIBLE); + PackageManager pm = mContext.getPackageManager(); + try { + row.icon.setImageDrawable(pm.getApplicationIcon(row.packageName)); + } catch (PackageManager.NameNotFoundException e) { + row.icon.setImageDrawable(pm.getDefaultActivityIcon()); + Log.e(TAG, "Failed to get icon of " + row.packageName, e); + } + } + + private void addExistingRows() { + int N = mRows.size(); + for (int i = 0; i < N; i++) { + final VolumeRow row = mRows.get(i); + initRow(row, row.stream, row.iconRes, row.iconMuteRes, row.important, + row.defaultStream); + if(!isAudioPanelOnLeftSide()){ + mDialogRowsView.addView(row.view, 0); + } else { + mDialogRowsView.addView(row.view); + } + updateVolumeRowH(row); + } + } + + private void cleanExpandedRows() { + for (int i = mRows.size() - 1; i >= 0; i--) { + final VolumeRow row = mRows.get(i); + if ((row.stream == AudioManager.STREAM_RING + || row.stream == AudioManager.STREAM_NOTIFICATION + || row.stream == AudioManager.STREAM_ALARM) && row.stream != mActiveStream) { + removeRow(row); + } + } + } + + private void removeRow(VolumeRow volumeRow) { + mRows.remove(volumeRow); + mDialogRowsView.removeView(volumeRow.view); + } + + private void updateAllActiveRows() { + int N = mRows.size(); + for (int i = 0; i < N; i++) { + updateVolumeRowH(mRows.get(i)); + } + } + + private VolumeRow getActiveRow() { + for (VolumeRow row : mRows) { + if (row.stream == mActiveStream) { + return row; + } + } + for (VolumeRow row : mRows) { + if (row.stream == STREAM_MUSIC) { + return row; + } + } + return mRows.get(0); + } + + private VolumeRow findRow(int stream) { + for (VolumeRow row : mRows) { + if (row.stream == stream) return row; + } + return null; + } + + public void dump(PrintWriter writer) { + writer.println(VolumeDialogImpl.class.getSimpleName() + " state:"); + writer.print(" mShowing: "); writer.println(mShowing); + writer.print(" mActiveStream: "); writer.println(mActiveStream); + writer.print(" mDynamic: "); writer.println(mDynamic); + writer.print(" mAutomute: "); writer.println(mAutomute); + writer.print(" mSilentMode: "); writer.println(mSilentMode); + } + + private static int getImpliedLevel(SeekBar seekBar, int progress) { + final int m = seekBar.getMax(); + final int n = m / 100 - 1; + final int level = progress == 0 ? 0 + : progress == m ? (m / 100) : (1 + (int)((progress / (float) m) * n)); + return level; + } + + @SuppressLint("InflateParams") + private void initRow(final VolumeRow row, final int stream, int iconRes, int iconMuteRes, + boolean important, boolean defaultStream) { + row.stream = stream; + row.iconRes = iconRes; + row.iconMuteRes = iconMuteRes; + row.important = important; + row.defaultStream = defaultStream; + row.view = LayoutInflater.from(mContext).inflate(R.layout.volume_dialog_oos_row, null); + row.view.setId(row.stream); + row.view.setTag(row); + row.header = row.view.findViewById(R.id.volume_row_header); + row.header.setId(20 * row.stream); + if (stream == STREAM_ACCESSIBILITY) { + row.header.setFilters(new InputFilter[] {new InputFilter.LengthFilter(13)}); + } + row.dndIcon = row.view.findViewById(R.id.dnd_icon); + row.slider = row.view.findViewById(R.id.volume_row_slider); + row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row)); + + row.anim = null; + + row.icon = row.view.findViewById(R.id.volume_row_icon); + Drawable iconResDrawable = mSysUIContext.getDrawable(iconRes); + row.icon.setVisibility(View.VISIBLE); + row.icon.setImageDrawable(iconResDrawable); + if (row.stream != AudioSystem.STREAM_ACCESSIBILITY) { + row.icon.setOnClickListener(v -> { + Events.writeEvent(Events.EVENT_ICON_CLICK, row.stream, row.iconState); + mController.setActiveStream(row.stream); + final boolean vmute = row.ss.level == row.ss.levelMin; + mController.setStreamVolume(stream, + vmute ? row.lastAudibleLevel : row.ss.levelMin); + row.userAttempt = 0; // reset the grace period, slider updates immediately + }); + } else { + row.icon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); + } + } + + private static boolean isBluetoothA2dpConnected() { + BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled() + && mBluetoothAdapter.getProfileConnectionState(BluetoothProfile.A2DP) + == BluetoothProfile.STATE_CONNECTED; + } + + private void updateOutputSwitcherVisibility() { + View dummyButton = mDialog.findViewById(R.id.dummy_button); + + if(isBluetoothA2dpConnected()) { + mMediaOutputIcon.setVisibility( + mActivityManager.getLockTaskModeState() == LOCK_TASK_MODE_NONE && + mExpanded ? VISIBLE : GONE); + dummyButton.setVisibility(GONE); + } else { + dummyButton.setVisibility( + mActivityManager.getLockTaskModeState() == LOCK_TASK_MODE_NONE && + mExpanded ? VISIBLE : GONE); + mMediaOutputIcon.setVisibility(GONE); + } + } + + private boolean shouldShowNotificationStream() { + ContentResolver ns = mContext.getContentResolver(); + return Settings.Secure.getInt(ns, Settings.Secure.VOLUME_LINK_NOTIFICATION, 1) == 1; + } + + public void initSettingsH() { + if (mMediaOutputIcon != null) { + mMediaOutputIcon.setOnClickListener(v -> { + Events.writeEvent(Events.EVENT_SETTINGS_CLICK); + Intent intent = new Intent(ACTION_MEDIA_OUTPUT); + dismissH(DISMISS_REASON_SETTINGS_CLICKED); + PluginDependency.get(this, ActivityStarter.class).startActivity(intent, + true /* dismissShade */); + }); + } + if (mExpandRowsView != null) { + mExpandRowsView.setVisibility( + mActivityManager.getLockTaskModeState() == LOCK_TASK_MODE_NONE ? + VISIBLE : GONE); + updateOutputSwitcherVisibility(); + } + if (mExpandRows != null) { + mExpandRows.setOnLongClickListener(v -> { + Events.writeEvent(Events.EVENT_SETTINGS_CLICK); + Intent intent = new Intent(Settings.Panel.ACTION_VOLUME); + dismissH(DISMISS_REASON_SETTINGS_CLICKED); + PluginDependency.get(this, ActivityStarter.class).startActivity(intent, + true /* dismissShade */); + return true; + }); + mExpandRows.setOnClickListener(v -> { + rescheduleTimeoutH(); + if (!mExpanded) { + addRow(AudioManager.STREAM_RING, mSysUIR.drawable("ic_volume_ringer"), + mSysUIR.drawable("ic_volume_ringer_mute"), true, false); + addRow(AudioManager.STREAM_ALARM, mSysUIR.drawable("ic_volume_alarm"), + mSysUIR.drawable("ic_volume_alarm_mute"), true, false); + if (!shouldShowNotificationStream()) { + addRow(AudioManager.STREAM_NOTIFICATION, mSysUIR.drawable("ic_volume_notification"), + mSysUIR.drawable("ic_volume_notification_mute"), true, false); + } + updateAllActiveRows(); + mExpanded = true; + updateOutputSwitcherVisibility(); + } else { + cleanExpandedRows(); + mExpanded = false; + updateOutputSwitcherVisibility(); + } + if (mAppVolume) { + updateAppRows(); + } + mExpandRows.setExpanded(mExpanded); + }); + } + } + private void updateAppRows() { + for (int i = mAppRows.size() - 1; i >= 0; i--) { + final VolumeRow row = mAppRows.get(i); + removeAppRow(row); + } + List<AppTrackData> trackDatas = mController.getAudioManager().listAppTrackDatas(); + for (AppTrackData data : trackDatas) { + if (data.isActive()) { + addAppRow(data); + } + } + } + + private void removeAppRow(VolumeRow volumeRow) { + mAppRows.remove(volumeRow); + mDialogRowsView.removeView(volumeRow.view); + } + + public void initRingerH() { + if (mRingerIcon != null) { + mRingerIcon.setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_POLITE); + mRingerIcon.setOnClickListener(v -> { + rescheduleTimeoutH(); + Prefs.putBoolean(mSysUIContext, Prefs.Key.TOUCHED_RINGER_TOGGLE, true); + final StreamState ss = mState.states.get(AudioManager.STREAM_RING); + if (ss == null) { + return; + } + // normal -> vibrate -> silent -> normal (skip vibrate if device doesn't have + // a vibrator. + int newRingerMode; + final boolean hasVibrator = mController.hasVibrator(); + if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) { + if (hasVibrator) { + newRingerMode = AudioManager.RINGER_MODE_VIBRATE; + } else { + newRingerMode = AudioManager.RINGER_MODE_SILENT; + } + } else if (mState.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE) { + newRingerMode = AudioManager.RINGER_MODE_SILENT; + } else { + newRingerMode = AudioManager.RINGER_MODE_NORMAL; + if (ss.level == 0) { + mController.setStreamVolume(AudioManager.STREAM_RING, 1); + } + } + Events.writeEvent(Events.EVENT_RINGER_TOGGLE, newRingerMode); + incrementManualToggleCount(); + updateRingerH(); + provideTouchFeedbackH(newRingerMode); + mController.setRingerMode(newRingerMode, false); + maybeShowToastH(newRingerMode); + }); + } + updateRingerH(); + } + + private void initODICaptionsH() { + if (mODICaptionsIcon != null) { + mODICaptionsIcon.setOnConfirmedTapListener(() -> { + onCaptionIconClicked(); + Events.writeEvent(Events.EVENT_ODI_CAPTIONS_CLICK); + }, mHandler); + } + + mController.getCaptionsComponentState(false); + } + + private void checkODICaptionsTooltip(boolean fromDismiss) { + if (!mHasSeenODICaptionsTooltip && !fromDismiss && mODICaptionsTooltipViewStub != null) { + mController.getCaptionsComponentState(true); + } else { + if (mHasSeenODICaptionsTooltip && fromDismiss && mODICaptionsTooltipView != null) { + hideCaptionsTooltip(); + } + } + } + + protected void showCaptionsTooltip() { + if (!mHasSeenODICaptionsTooltip && mODICaptionsTooltipViewStub != null) { + mODICaptionsTooltipView = mODICaptionsTooltipViewStub.inflate(); + mODICaptionsTooltipView.findViewById(R.id.dismiss).setOnClickListener(v -> { + hideCaptionsTooltip(); + Events.writeEvent(Events.EVENT_ODI_CAPTIONS_TOOLTIP_CLICK); + }); + mODICaptionsTooltipViewStub = null; + rescheduleTimeoutH(); + } + + if (mODICaptionsTooltipView != null) { + mODICaptionsTooltipView.setAlpha(0.f); + mODICaptionsTooltipView.animate() + .alpha(1.f) + .setStartDelay(DIALOG_SHOW_ANIMATION_DURATION) + .withEndAction(() -> { + if (D.BUG) Log.d(TAG, "tool:checkODICaptionsTooltip() putBoolean true"); + Prefs.putBoolean(mSysUIContext, + Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, true); + mHasSeenODICaptionsTooltip = true; + if (mODICaptionsIcon != null) { + mODICaptionsIcon + .postOnAnimation(getSinglePressFor(mODICaptionsIcon)); + } + }) + .start(); + } + } + + private void hideCaptionsTooltip() { + if (mODICaptionsTooltipView != null && mODICaptionsTooltipView.getVisibility() == VISIBLE) { + mODICaptionsTooltipView.animate().cancel(); + mODICaptionsTooltipView.setAlpha(1.f); + mODICaptionsTooltipView.animate() + .alpha(0.f) + .setStartDelay(0) + .setDuration(DIALOG_HIDE_ANIMATION_DURATION) + .withEndAction(() -> mODICaptionsTooltipView.setVisibility(INVISIBLE)) + .start(); + } + } + + protected void tryToRemoveCaptionsTooltip() { + if (mHasSeenODICaptionsTooltip && mODICaptionsTooltipView != null) { + ViewGroup container = mDialog.findViewById(R.id.volume_dialog_container); + container.removeView(mODICaptionsTooltipView); + mODICaptionsTooltipView = null; + } + } + + private void updateODICaptionsH(boolean isServiceComponentEnabled, boolean fromTooltip) { + if (mODICaptionsView != null) { + mODICaptionsView.setVisibility(isServiceComponentEnabled ? VISIBLE : GONE); + } + + if (!isServiceComponentEnabled) return; + + updateCaptionsIcon(); + if (fromTooltip) showCaptionsTooltip(); + } + + private void updateCaptionsIcon() { + boolean captionsEnabled = mController.areCaptionsEnabled(); + if (mODICaptionsIcon.getCaptionsEnabled() != captionsEnabled) { + mODICaptionsIcon.setCaptionsEnabled(captionsEnabled); + } + + boolean isOptedOut = mController.isCaptionStreamOptedOut(); + if (mODICaptionsIcon.getOptedOut() != isOptedOut) { + mHandler.post(() -> mODICaptionsIcon.setOptedOut(isOptedOut)); + } + } + + private void onCaptionIconClicked() { + boolean isEnabled = mController.areCaptionsEnabled(); + mController.setCaptionsEnabled(!isEnabled); + updateCaptionsIcon(); + } + + private void incrementManualToggleCount() { + ContentResolver cr = mContext.getContentResolver(); + int ringerCount = Settings.Secure.getInt(cr, Settings.Secure.MANUAL_RINGER_TOGGLE_COUNT, 0); + Settings.Secure.putInt(cr, Settings.Secure.MANUAL_RINGER_TOGGLE_COUNT, ringerCount + 1); + } + + private void provideTouchFeedbackH(int newRingerMode) { + VibrationEffect effect = null; + switch (newRingerMode) { + case RINGER_MODE_NORMAL: + mController.scheduleTouchFeedback(); + break; + case RINGER_MODE_SILENT: + effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); + break; + case RINGER_MODE_VIBRATE: + default: + effect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK); + } + if (effect != null) { + mController.vibrate(effect); + } + } + + private void maybeShowToastH(int newRingerMode) { + int seenToastCount = Prefs.getInt(mSysUIContext, Prefs.Key.SEEN_RINGER_GUIDANCE_COUNT, 0); + + if (seenToastCount > VolumePrefs.SHOW_RINGER_TOAST_COUNT) { + return; + } + CharSequence toastText = null; + switch (newRingerMode) { + case RINGER_MODE_NORMAL: + final StreamState ss = mState.states.get(AudioManager.STREAM_RING); + if (ss != null) { + toastText = mSysUIContext.getString( + mSysUIR.string("volume_dialog_ringer_guidance_ring"), + Utils.formatPercentage(ss.level, ss.levelMax)); + } + break; + case RINGER_MODE_SILENT: + toastText = mSysUIContext.getString( + com.android.internal.R.string.volume_dialog_ringer_guidance_silent); + break; + case RINGER_MODE_VIBRATE: + default: + toastText = mSysUIContext.getString( + com.android.internal.R.string.volume_dialog_ringer_guidance_vibrate); + } + + Toast.makeText(mContext, toastText, Toast.LENGTH_SHORT).show(); + seenToastCount++; + Prefs.putInt(mSysUIContext, Prefs.Key.SEEN_RINGER_GUIDANCE_COUNT, seenToastCount); + } + + public void show(int reason) { + mHandler.obtainMessage(H.SHOW, reason, 0).sendToTarget(); + } + + public void dismiss(int reason) { + mHandler.obtainMessage(H.DISMISS, reason, 0).sendToTarget(); + } + + private void showH(int reason) { + if (D.BUG) Log.d(TAG, "showH r=" + Events.SHOW_REASONS[reason]); + mHandler.removeMessages(H.SHOW); + mHandler.removeMessages(H.DISMISS); + rescheduleTimeoutH(); + + if (mConfigChanged) { + initDialog(); // resets mShowing to false + mConfigurableTexts.update(); + mConfigChanged = false; + } + + initSettingsH(); + mDialog.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsListener); + + if(!mShowing && !mDialog.isShown()) { + if (!isLandscape()) mDialogView.setTranslationX((mDialogView.getWidth() / 2.0f)*(isAudioPanelOnLeftSide() ? -1 : 1)); + mDialogView.setAlpha(0); + mDialogView.animate() + .alpha(1) + .translationX(0) + .setDuration(DIALOG_SHOW_ANIMATION_DURATION) + .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator()) + .withStartAction(() -> { + if(!mDialog.isShown()) { + mWindowManager.addView(mDialog, mWindowParams); + } + }) + .withEndAction(() -> { + if (!Prefs.getBoolean(mSysUIContext, Prefs.Key.TOUCHED_RINGER_TOGGLE, false)) { + if (mRingerIcon != null) { + mRingerIcon.postOnAnimationDelayed( + getSinglePressFor(mRingerIcon), 1500); + } + } + mShowing = true; + }) + .start(); + } + Events.writeEvent(Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked()); + mController.notifyVisible(true); + mController.getCaptionsComponentState(false); + checkODICaptionsTooltip(false); + } + + protected void rescheduleTimeoutH() { + mHandler.removeMessages(H.DISMISS); + final int timeout = computeTimeoutH(); + mHandler.sendMessageDelayed(mHandler + .obtainMessage(H.DISMISS, Events.DISMISS_REASON_TIMEOUT, 0), timeout); + if (D.BUG) Log.d(TAG, "rescheduleTimeout " + timeout + " " + Debug.getCaller()); + mController.userActivity(); + } + + private int computeTimeoutH() { + if (mHovering) { + return mAccessibilityMgr.getRecommendedTimeoutMillis(DIALOG_HOVERING_TIMEOUT_MILLIS, + AccessibilityManager.FLAG_CONTENT_CONTROLS); + } + if (mSafetyWarning != null) { + return mAccessibilityMgr.getRecommendedTimeoutMillis( + DIALOG_SAFETYWARNING_TIMEOUT_MILLIS, + AccessibilityManager.FLAG_CONTENT_TEXT + | AccessibilityManager.FLAG_CONTENT_CONTROLS); + } + if (!mHasSeenODICaptionsTooltip && mODICaptionsTooltipView != null) { + return mAccessibilityMgr.getRecommendedTimeoutMillis( + DIALOG_ODI_CAPTIONS_TOOLTIP_TIMEOUT_MILLIS, + AccessibilityManager.FLAG_CONTENT_TEXT + | AccessibilityManager.FLAG_CONTENT_CONTROLS); + } + return mAccessibilityMgr.getRecommendedTimeoutMillis(DIALOG_TIMEOUT_MILLIS, + AccessibilityManager.FLAG_CONTENT_CONTROLS); + } + + protected void dismissH(int reason) { + if (D.BUG) { + Log.d(TAG, "mDialog.dismiss() reason: " + Events.DISMISS_REASONS[reason] + + " from: " + Debug.getCaller()); + } + if (!mShowing) { + // This may happen when dismissing an expanded panel, don't animate again + return; + } + mHandler.removeMessages(H.DISMISS); + mHandler.removeMessages(H.SHOW); + mDialogView.animate().cancel(); + if (mShowing) { + mShowing = false; + // Only logs when the volume dialog visibility is changed. + Events.writeEvent(Events.EVENT_DISMISS_DIALOG, reason); + } + mDialogView.setTranslationX(0); + mDialogView.setAlpha(1); + ViewPropertyAnimator animator = mDialogView.animate() + .alpha(0) + .setDuration(DIALOG_HIDE_ANIMATION_DURATION) + .setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator()) + .withEndAction(() -> mHandler.postDelayed(() -> { + if(mDialog.isShown()){ + mWindowManager.removeViewImmediate(mDialog); + } + cleanExpandedRows(); + mExpanded = false; + mExpandRows.setExpanded(mExpanded); + tryToRemoveCaptionsTooltip(); + }, 50)); + if (!isLandscape()) animator.translationX((mDialogView.getWidth() / 2.0f)*(isAudioPanelOnLeftSide() ? -1 : 1)); + animator.start(); + mDialog.getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsListener); + checkODICaptionsTooltip(true); + mController.notifyVisible(false); + synchronized (mSafetyWarningLock) { + if (mSafetyWarning != null) { + if (D.BUG) Log.d(TAG, "SafetyWarning dismissed"); + mSafetyWarning.dismiss(); + } + } + } + + private boolean showActiveStreamOnly() { + return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK) + || mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEVISION); + } + + private boolean shouldBeVisibleH(VolumeRow row, VolumeRow activeRow) { + boolean isActive = row.stream == activeRow.stream; + + if (isActive) { + return true; + } + + if (!mShowActiveStreamOnly) { + if (row.stream == AudioSystem.STREAM_ACCESSIBILITY) { + return mShowA11yStream; + } + + // if the active row is accessibility, then continue to display previous + // active row since accessibility is displayed under it + if (activeRow.stream == AudioSystem.STREAM_ACCESSIBILITY && + row.stream == mPrevActiveStream) { + return true; + } + + if (row.defaultStream) { + return activeRow.stream == STREAM_RING + || activeRow.stream == STREAM_ALARM + || activeRow.stream == STREAM_VOICE_CALL + || activeRow.stream == STREAM_ACCESSIBILITY + || mDynamic.get(activeRow.stream); + } + } + + return false; + } + + private void updateRowsH(final VolumeRow activeRow) { + if (D.BUG) Log.d(TAG, "updateRowsH"); + if (!mShowing) { + trimObsoleteH(); + } + // apply changes to all rows + for (final VolumeRow row : mRows) { + final boolean isActive = row == activeRow; + final boolean shouldBeVisible = shouldBeVisibleH(row, activeRow); + if (!mExpanded) { + Utils.setVisOrGone(row.view, shouldBeVisible); + } + if (row.view.isShown()) { + updateVolumeRowTintH(row, isActive); + } + } + } + + protected void updateRingerH() { + if (mState != null) { + final StreamState ss = mState.states.get(AudioManager.STREAM_RING); + if (ss == null) { + return; + } + + boolean isZenMuted = mState.zenMode == Global.ZEN_MODE_ALARMS + || mState.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS + || (mState.zenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS + && mState.disallowRinger); + enableRingerViewsH(!isZenMuted); + Drawable ringerDrawable; + switch (mState.ringerModeInternal) { + case AudioManager.RINGER_MODE_VIBRATE: + mModeIndicator.setVisibility(VISIBLE); + mModeIndicator.setText(R.string.volume_ringer_hint_vibrating); + ringerDrawable = mSysUIContext.getDrawable( + mSysUIR.drawable("ic_volume_ringer_vibrate")); + addAccessibilityDescription(mRingerIcon, RINGER_MODE_VIBRATE, + mSysUIContext.getString(mSysUIR.string("volume_ringer_hint_mute"))); + mRingerIcon.setTag(Events.ICON_STATE_VIBRATE); + break; + case AudioManager.RINGER_MODE_SILENT: + mModeIndicator.setVisibility(VISIBLE); + mModeIndicator.setText(R.string.volume_ringer_hint_muted); + ringerDrawable = mSysUIContext.getDrawable( + mSysUIR.drawable("ic_volume_ringer_mute")); + mRingerIcon.setTag(Events.ICON_STATE_MUTE); + addAccessibilityDescription(mRingerIcon, RINGER_MODE_SILENT, + mSysUIContext.getString(mSysUIR.string("volume_ringer_hint_unmute"))); + break; + case AudioManager.RINGER_MODE_NORMAL: + default: + boolean muted = (mAutomute && ss.level == 0) || ss.muted; + if (!isZenMuted && muted) { + mModeIndicator.setVisibility(VISIBLE); + mModeIndicator.setText(R.string.volume_ringer_hint_muted); + ringerDrawable = mSysUIContext.getDrawable( + mSysUIR.drawable("ic_volume_ringer_mute")); + addAccessibilityDescription(mRingerIcon, RINGER_MODE_NORMAL, + mSysUIContext.getString(mSysUIR.string("volume_ringer_hint_unmute"))); + mRingerIcon.setTag(Events.ICON_STATE_MUTE); + } else { + mModeIndicator.setVisibility(VISIBLE); + mModeIndicator.setText(R.string.volume_ringer_hint_unmuted); + ringerDrawable = mSysUIContext.getDrawable( + mSysUIR.drawable("ic_volume_ringer")); + if (mController.hasVibrator()) { + addAccessibilityDescription(mRingerIcon, RINGER_MODE_NORMAL, + mSysUIContext.getString(mSysUIR.string("volume_ringer_hint_vibrate"))); + } else { + addAccessibilityDescription(mRingerIcon, RINGER_MODE_NORMAL, + mSysUIContext.getString(mSysUIR.string("volume_ringer_hint_mute"))); + } + mRingerIcon.setTag(Events.ICON_STATE_UNMUTE); + } + break; + } + mRingerIcon.setImageDrawable(ringerDrawable); + } + } + + private void addAccessibilityDescription(View view, int currState, String hintLabel) { + int currStateResId; + switch (currState) { + case RINGER_MODE_SILENT: + currStateResId = mSysUIR.string("volume_ringer_status_silent"); + break; + case RINGER_MODE_VIBRATE: + currStateResId = mSysUIR.string("volume_ringer_status_vibrate"); + break; + case RINGER_MODE_NORMAL: + default: + currStateResId = mSysUIR.string("volume_ringer_status_normal"); + } + + view.setContentDescription(mSysUIContext.getString(currStateResId)); + view.setAccessibilityDelegate(new AccessibilityDelegate() { + public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(host, info); + info.addAction(new AccessibilityNodeInfo.AccessibilityAction( + AccessibilityNodeInfo.ACTION_CLICK, hintLabel)); + } + }); + } + + /** + * Toggles enable state of views in a VolumeRow (not including seekbar or icon) + * Hides/shows zen icon + * @param enable whether to enable volume row views and hide dnd icon + */ + private void enableVolumeRowViewsH(VolumeRow row, boolean enable) { + boolean showDndIcon = !enable; + row.dndIcon.setVisibility(showDndIcon ? VISIBLE : GONE); + } + + /** + * Toggles enable state of footer/ringer views + * Hides/shows zen icon + * @param enable whether to enable ringer views and hide dnd icon + */ + private void enableRingerViewsH(boolean enable) { + if (mRingerIcon != null) { + mRingerIcon.setEnabled(enable); + } + if (mZenIcon != null) { + mZenIcon.setVisibility(enable ? GONE : VISIBLE); + } + } + + private void trimObsoleteH() { + if (D.BUG) Log.d(TAG, "trimObsoleteH"); + for (int i = mRows.size() - 1; i >= 0; i--) { + final VolumeRow row = mRows.get(i); + if (row.ss == null || !row.ss.dynamic) continue; + if (!mDynamic.get(row.stream)) { + mRows.remove(i); + mDialogRowsView.removeView(row.view); + } + } + } + + protected void onStateChangedH(State state) { + if (D.BUG) Log.d(TAG, "onStateChangedH() state: " + state.toString()); + if (mState != null && state != null + && mState.ringerModeInternal != state.ringerModeInternal + && state.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE) { + mController.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK)); + } + + mState = state; + mDynamic.clear(); + // add any new dynamic rows + for (int i = 0; i < state.states.size(); i++) { + final int stream = state.states.keyAt(i); + final StreamState ss = state.states.valueAt(i); + if (!ss.dynamic) continue; + mDynamic.put(stream, true); + if (findRow(stream) == null) { + addRow(stream, mSysUIR.drawable("ic_volume_remote"), + mSysUIR.drawable("ic_volume_remote_mute"), true, + false, true); + } + } + + if (mActiveStream != state.activeStream) { + mPrevActiveStream = mActiveStream; + mActiveStream = state.activeStream; + VolumeRow activeRow = getActiveRow(); + updateRowsH(activeRow); + if (mShowing) rescheduleTimeoutH(); + } + for (VolumeRow row : mRows) { + updateVolumeRowH(row); + } + updateRingerH(); + } + + CharSequence composeWindowTitle() { + return mSysUIContext.getString(mSysUIR.string("volume_dialog_title"), getStreamLabelH(getActiveRow().ss)); + } + + private void updateVolumeRowH(VolumeRow row) { + if (D.BUG) Log.i(TAG, "updateVolumeRowH s=" + row.stream); + if (mState == null) return; + final StreamState ss = mState.states.get(row.stream); + if (ss == null) return; + row.ss = ss; + if (ss.level > ss.levelMin) { + row.lastAudibleLevel = ss.level; + } + if (ss.level == row.requestedLevel) { + row.requestedLevel = -1; + } + final boolean isA11yStream = row.stream == STREAM_ACCESSIBILITY; + final boolean isRingStream = row.stream == AudioManager.STREAM_RING; + final boolean isSystemStream = row.stream == AudioManager.STREAM_SYSTEM; + final boolean isAlarmStream = row.stream == STREAM_ALARM; + final boolean isMusicStream = row.stream == AudioManager.STREAM_MUSIC; + final boolean isMuted = row.ss.level == row.ss.levelMin; + final boolean isRingVibrate = isRingStream + && mState.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE; + final boolean isRingSilent = isRingStream + && mState.ringerModeInternal == AudioManager.RINGER_MODE_SILENT; + final boolean isZenPriorityOnly = mState.zenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + final boolean isZenAlarms = mState.zenMode == Global.ZEN_MODE_ALARMS; + final boolean isZenNone = mState.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS; + final boolean zenMuted = isZenAlarms ? (isRingStream || isSystemStream) + : isZenNone ? (isRingStream || isSystemStream || isAlarmStream || isMusicStream) + : isZenPriorityOnly ? ((isAlarmStream && mState.disallowAlarms) || + (isMusicStream && mState.disallowMedia) || + (isRingStream && mState.disallowRinger) || + (isSystemStream && mState.disallowSystem)) + : false; + + // update slider max + final int max = ss.levelMax * 100; + if (max != row.slider.getMax()) { + row.slider.setMax(max); + } + // update slider min + final int min = ss.levelMin * 100; + if (min != row.slider.getMin()) { + row.slider.setMin(min); + } + + // update header text + Utils.setText(row.header, getStreamLabelH(ss)); + row.slider.setContentDescription(row.header.getText()); + mConfigurableTexts.add(row.header, ss.name); + + // update icon + final boolean iconEnabled = (mAutomute || ss.muteSupported) && !zenMuted; + row.icon.setEnabled(iconEnabled); + final int iconRes = + isRingVibrate ? mSysUIR.drawable("ic_volume_ringer_vibrate") + : isRingSilent || zenMuted ? row.iconMuteRes + : ss.routedToBluetooth ? + (ss.muted ? mSysUIR.drawable("ic_volume_media_bt_mute") + : mSysUIR.drawable("ic_volume_media_bt")) + : mAutomute && ss.level == 0 ? row.iconMuteRes + : isMuted ? row.iconMuteRes : row.iconRes; + Drawable iconResDrawable = mSysUIContext.getDrawable(iconRes); + row.icon.setImageDrawable(iconResDrawable); + row.iconState = + iconRes == mSysUIR.drawable("ic_volume_ringer_vibrate") ? Events.ICON_STATE_VIBRATE + : (iconRes == mSysUIR.drawable("ic_volume_media_bt_mute") || iconRes == row.iconMuteRes) + ? Events.ICON_STATE_MUTE + : (iconRes == mSysUIR.drawable("ic_volume_media_bt") || iconRes == row.iconRes) + ? Events.ICON_STATE_UNMUTE + : Events.ICON_STATE_UNKNOWN; + if (iconEnabled) { + if (isRingStream) { + if (isRingVibrate) { + row.icon.setContentDescription(mSysUIContext.getString( + mSysUIR.string("volume_stream_content_description_unmute"), + getStreamLabelH(ss))); + } else { + if (mController.hasVibrator()) { + row.icon.setContentDescription(mSysUIContext.getString( + mShowA11yStream + ? mSysUIR.string("volume_stream_content_description_vibrate_a11y") + : mSysUIR.string("volume_stream_content_description_vibrate"), + getStreamLabelH(ss))); + } else { + row.icon.setContentDescription(mSysUIContext.getString( + mShowA11yStream + ? mSysUIR.string("volume_stream_content_description_mute_a11y") + : mSysUIR.string("volume_stream_content_description_mute"), + getStreamLabelH(ss))); + } + } + } else if (isA11yStream) { + row.icon.setContentDescription(getStreamLabelH(ss)); + } else { + if (ss.muted || mAutomute && ss.level == 0) { + row.icon.setContentDescription(mSysUIContext.getString( + mSysUIR.string("volume_stream_content_description_unmute"), + getStreamLabelH(ss))); + } else { + row.icon.setContentDescription(mSysUIContext.getString( + mShowA11yStream + ? mSysUIR.string("volume_stream_content_description_mute_a11y") + : mSysUIR.string("volume_stream_content_description_mute"), + getStreamLabelH(ss))); + } + } + } else { + row.icon.setContentDescription(getStreamLabelH(ss)); + } + + // ensure tracking is disabled if zenMuted + if (zenMuted) { + row.tracking = false; + } + enableVolumeRowViewsH(row, !zenMuted); + + // update slider + final boolean enableSlider = !zenMuted; + final int vlevel = row.ss.muted && (!isRingStream && !zenMuted) ? 0 + : row.ss.level; + updateVolumeRowSliderH(row, enableSlider, vlevel); + } + + private void updateVolumeRowTintH(VolumeRow row, boolean isActive) { + if (isActive) { + row.slider.requestFocus(); + } + boolean useActiveColoring = isActive && row.slider.isEnabled(); + final ColorStateList tint = useActiveColoring + ? Utils.getColorAccent(mContext) + : Utils.getColorAttr(mContext, android.R.attr.colorForeground); + final int alpha = useActiveColoring + ? Color.alpha(tint.getDefaultColor()) + : getAlphaAttr(android.R.attr.secondaryContentAlpha); + if (tint == row.cachedTint) return; + row.slider.setProgressTintList(tint); + row.slider.setThumbTintList(tint); + row.slider.setAlpha(((float) alpha) / 255); + row.cachedTint = tint; + } + + private void updateVolumeRowSliderH(VolumeRow row, boolean enable, int vlevel) { + row.slider.setEnabled(enable); + updateVolumeRowTintH(row, row.stream == mActiveStream); + if (row.tracking) { + return; // don't update if user is sliding + } + final int progress = row.slider.getProgress(); + final int level = getImpliedLevel(row.slider, progress); + final boolean rowVisible = row.view.getVisibility() == VISIBLE; + final boolean inGracePeriod = (SystemClock.uptimeMillis() - row.userAttempt) + < USER_ATTEMPT_GRACE_PERIOD; + mHandler.removeMessages(H.RECHECK, row); + if (mShowing && rowVisible && inGracePeriod) { + if (D.BUG) Log.d(TAG, "inGracePeriod"); + mHandler.sendMessageAtTime(mHandler.obtainMessage(H.RECHECK, row), + row.userAttempt + USER_ATTEMPT_GRACE_PERIOD); + return; // don't update if visible and in grace period + } + if (vlevel == level) { + if (mShowing && rowVisible) { + return; // don't clamp if visible + } + } + final int newProgress = vlevel * 100; + if (progress != newProgress) { + if (mShowing && rowVisible) { + // animate! + if (row.anim != null && row.anim.isRunning() + && row.animTargetProgress == newProgress) { + return; // already animating to the target progress + } + // start/update animation + if (row.anim == null) { + row.anim = ObjectAnimator.ofInt(row.slider, "progress", progress, newProgress); + row.anim.setInterpolator(new DecelerateInterpolator()); + } else { + row.anim.cancel(); + row.anim.setIntValues(progress, newProgress); + } + row.animTargetProgress = newProgress; + row.anim.setDuration(UPDATE_ANIMATION_DURATION); + row.anim.start(); + } else { + // update slider directly to clamped value + if (row.anim != null) { + row.anim.cancel(); + } + row.slider.setProgress(newProgress, true); + } + } + } + + private void recheckH(VolumeRow row) { + if (row == null) { + if (D.BUG) Log.d(TAG, "recheckH ALL"); + trimObsoleteH(); + for (VolumeRow r : mRows) { + updateVolumeRowH(r); + } + } else { + if (D.BUG) Log.d(TAG, "recheckH " + row.stream); + updateVolumeRowH(row); + } + } + + private void setStreamImportantH(int stream, boolean important) { + for (VolumeRow row : mRows) { + if (row.stream == stream) { + row.important = important; + return; + } + } + } + + private void showSafetyWarningH(int flags) { + if ((flags & (AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_SHOW_UI_WARNINGS)) != 0 + || mShowing) { + synchronized (mSafetyWarningLock) { + if (mSafetyWarning != null) { + return; + } + mSafetyWarning = new SafetyWarningDialog(mContext, mController.getAudioManager()) { + @Override + protected void cleanUp() { + synchronized (mSafetyWarningLock) { + mSafetyWarning = null; + } + recheckH(null); + } + }; + mSafetyWarning.show(); + } + recheckH(null); + } + rescheduleTimeoutH(); + } + + private String getStreamLabelH(StreamState ss) { + if (ss == null) { + return ""; + } + if (ss.remoteLabel != null) { + return ss.remoteLabel; + } + try { + return mSysUIContext.getString(ss.name); + } catch (Resources.NotFoundException e) { + Slog.e(TAG, "Can't find translation for stream " + ss); + return ""; + } + } + + private Runnable getSinglePressFor(ImageButton button) { + return () -> { + if (button != null) { + button.setPressed(true); + button.postOnAnimationDelayed(getSingleUnpressFor(button), 200); + } + }; + } + + private Runnable getSingleUnpressFor(ImageButton button) { + return () -> { + if (button != null) { + button.setPressed(false); + } + }; + } + + private final VolumeDialogController.Callbacks mControllerCallbackH + = new VolumeDialogController.Callbacks() { + @Override + public void onShowRequested(int reason) { + showH(reason); + } + + @Override + public void onDismissRequested(int reason) { + dismissH(reason); + } + + @Override + public void onScreenOff() { + dismissH(Events.DISMISS_REASON_SCREEN_OFF); + } + + @Override + public void onStateChanged(State state) { + onStateChangedH(state); + } + + @Override + public void onLayoutDirectionChanged(int layoutDirection) { + mDialogView.setLayoutDirection(layoutDirection); + } + + @Override + public void onConfigurationChanged() { + if(mDialog.isShown()) { + mWindowManager.removeViewImmediate(mDialog); + } + mConfigChanged = true; + } + + @Override + public void onShowVibrateHint() { + if (mSilentMode) { + mController.setRingerMode(AudioManager.RINGER_MODE_SILENT, false); + } + } + + @Override + public void onShowSilentHint() { + if (mSilentMode) { + mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false); + } + } + + @Override + public void onShowSafetyWarning(int flags) { + showSafetyWarningH(flags); + } + + @Override + public void onAccessibilityModeChanged(Boolean showA11yStream) { + mShowA11yStream = showA11yStream == null ? false : showA11yStream; + VolumeRow activeRow = getActiveRow(); + if (!mShowA11yStream && STREAM_ACCESSIBILITY == activeRow.stream) { + dismissH(Events.DISMISS_STREAM_GONE); + } else { + updateRowsH(activeRow); + } + + } + + @Override + public void onCaptionComponentStateChanged( + Boolean isComponentEnabled, Boolean fromTooltip) { + updateODICaptionsH(isComponentEnabled, fromTooltip); + } + }; + + private final class H extends Handler { + private static final int SHOW = 1; + private static final int DISMISS = 2; + private static final int RECHECK = 3; + private static final int RECHECK_ALL = 4; + private static final int SET_STREAM_IMPORTANT = 5; + private static final int RESCHEDULE_TIMEOUT = 6; + private static final int STATE_CHANGED = 7; + + public H() { + super(Looper.getMainLooper()); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case SHOW: showH(msg.arg1); break; + case DISMISS: dismissH(msg.arg1); break; + case RECHECK: recheckH((VolumeRow) msg.obj); break; + case RECHECK_ALL: recheckH(null); break; + case SET_STREAM_IMPORTANT: setStreamImportantH(msg.arg1, msg.arg2 != 0); break; + case RESCHEDULE_TIMEOUT: rescheduleTimeoutH(); break; + case STATE_CHANGED: onStateChangedH(mState); break; + } + } + } + + private final class VolumeSeekBarChangeListener implements OnSeekBarChangeListener { + private final VolumeRow mRow; + + private VolumeSeekBarChangeListener(VolumeRow row) { + mRow = row; + } + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + rescheduleTimeoutH(); + if (D.BUG) Log.d(TAG, AudioSystem.streamToString(mRow.stream) + + " onProgressChanged " + progress + " fromUser=" + fromUser); + if (mRow.isAppVolumeRow) { + mController.getAudioManager().setAppVolume(mRow.packageName, progress * 0.01f); + return; + } + if (mRow.ss == null) return; + if (!fromUser) return; + if (mRow.ss.levelMin > 0) { + final int minProgress = mRow.ss.levelMin * 100; + if (progress < minProgress) { + seekBar.setProgress(minProgress); + progress = minProgress; + } + } + final int userLevel = getImpliedLevel(seekBar, progress); + if (mRow.ss.level != userLevel || mRow.ss.muted && userLevel > 0) { + mRow.userAttempt = SystemClock.uptimeMillis(); + if (mRow.requestedLevel != userLevel) { + mController.setActiveStream(mRow.stream); + mController.setStreamVolume(mRow.stream, userLevel); + mRow.requestedLevel = userLevel; + Events.writeEvent(Events.EVENT_TOUCH_LEVEL_CHANGED, mRow.stream, + userLevel); + } + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + mRow.tracking = true; + if (mRow.isAppVolumeRow) return; + if (D.BUG) Log.d(TAG, "onStartTrackingTouch"+ " " + mRow.stream); + mController.setActiveStream(mRow.stream); + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + if (D.BUG) Log.d(TAG, "onStopTrackingTouch"+ " " + mRow.stream); + mRow.tracking = false; + if (mRow.isAppVolumeRow) return; + mRow.userAttempt = SystemClock.uptimeMillis(); + final int userLevel = getImpliedLevel(seekBar, seekBar.getProgress()); + Events.writeEvent(Events.EVENT_TOUCH_LEVEL_DONE, mRow.stream, userLevel); + if (mRow.ss.level != userLevel) { + mHandler.sendMessageDelayed(mHandler.obtainMessage(H.RECHECK, mRow), + USER_ATTEMPT_GRACE_PERIOD); + } + } + } + + private final class Accessibility extends AccessibilityDelegate { + public void init() { + mDialogView.setAccessibilityDelegate(this); + } + + @Override + public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { + // Activities populate their title here. Follow that example. + event.getText().add(composeWindowTitle()); + return true; + } + + @Override + public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, + AccessibilityEvent event) { + rescheduleTimeoutH(); + return super.onRequestSendAccessibilityEvent(host, child, event); + } + } + + private boolean isAudioPanelOnLeftSide() { + return mLeftVolumeRocker; + } + + private static class VolumeRow { + private View view; + private TextView header; + private ImageButton icon; + private SeekBar slider; + private int stream; + private StreamState ss; + private long userAttempt; // last user-driven slider change + private boolean tracking; // tracking slider touch + private int requestedLevel = -1; // pending user-requested level via progress changed + private int iconRes; + private int iconMuteRes; + private boolean important; + private boolean defaultStream; + private ColorStateList cachedTint; + private int iconState; // from Events + private ObjectAnimator anim; // slider progress animation for non-touch-related updates + private int animTargetProgress; + private int lastAudibleLevel = 2; + private FrameLayout dndIcon; + /* for change app's volume */ + private String packageName; + private boolean isAppVolumeRow = false; + private boolean appMuted; + } +} diff --git a/product_packages_volume_panels.mk b/product_packages_volume_panels.mk index d06cdd5..4622e57 100644 --- a/product_packages_volume_panels.mk +++ b/product_packages_volume_panels.mk @@ -2,5 +2,6 @@ PRODUCT_PACKAGES += \ AospPanel \ CompactPanel \ MiuiCompactPanel \ + OosPanel \ OreoPanel \ TiledPanel |
