diff options
author | HrX03 <dn.bianco03@gmail.com> | 2019-03-07 17:50:40 +0000 |
---|---|---|
committer | alk3pInjection <webmaster@raspii.tech> | 2021-09-27 21:17:05 +0800 |
commit | 05568d9edda0458d238f3d962c9ed3e10ee4dd15 (patch) | |
tree | d3d91ec86ce75f4d76754b4567860020ebbb7612 | |
parent | 41fa200574b0a00085569d47dda7dcb5bcfea0f9 (diff) |
[aospa][quartz] SystemUI: Redesign volume dialog
Inspiration from MiUI, iOS and Dil3mm4
Change-Id: I8bddda04c83c995bec82e9493017db69bd460b34
Co-Authored-By: Andrew Fluck <andrew@aospa.co>
Co-Authored-By: rituj <ritujbeniwal@gmail.com>
Co-Authored-By: Jyotiraditya <jyotiraditya@aospa.co>
Co-Authored-By: Akash Srivastava <akashsrivastava@aospa.co>
Co-Authored-By: 00day0 <therandomuser11@gmail.com>
Co-authored-by: Kshitij Gupta <kshitijgm@gmail.com>
base: Redo expanded volume panel for 10.x
[ HrX03 | AgentFabulous - POSP ]
- Google nuked expanded volume panel in pie. Redo the current
implementation to bring this back from the past and dejank it.
- Back to Android 8.x functionality!
Change-Id: Ie4931a4ae09483ba737a74fc32ed0a1f6acf105d
Co-authored-by: Kshitij Gupta <kshitijgm@gmail.com>
Signed-off-by: Arian <arian.kulmer@web.de>
SystemUI: VolumePanel: Version 1.1
* Add support for unlinked notification volume
* Fix progress bar inconsistencies when switching ringer modes
* Some minor animation tweaks
Change-Id: I31f87aacb7fbb445dd3b03ceb5064263e5af4836
VolumeDialogImpl: fix ConcurrentModificationException
SDB: it's happening to only a few users and let make those fc free
msg: java.util.ConcurrentModificationException
stacktrace: java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.next(ArrayList.java:860)
at com.android.systemui.volume.VolumeDialogImpl.updateMediaOutputViewH(VolumeDialogImpl.java:905)
at com.android.systemui.volume.VolumeDialogImpl.access$4800(VolumeDialogImpl.java:120)
at com.android.systemui.volume.VolumeDialogImpl$H.handleMessage(VolumeDialogImpl.java:1912)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7657)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:594)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
VolumePluginManager: Fix fc for stock panel
Change-Id: Ib0f6340ac7fea08abc637a1c3391a58cc4f1dfb6
VolumeDialogImpl: Reschedule the timeout on clicks on captions
Change-Id: Ie98813a91396f3c3a84aeac8a609071c5cc315f6
VolumePanel: Fix glitchy ringer and notif bar when switching modes
Co-Authored-By: Andrew Fluck <andrew@aospa.co>
Co-Authored-By: rituj <ritujbeniwal@gmail.com>
Co-Authored-By: Jyotiraditya <jyotiraditya@aospa.co>
Co-Authored-By: Akash Srivastava <akashsrivastava@aospa.co>
Co-Authored-By: 00day0 <therandomuser11@gmail.com>
Co-authored-by: Kshitij Gupta <kshitijgm@gmail.com>
Signed-off-by: rituj <ritujbeniwal@gmail.com>
Signed-off-by: Arian <arian.kulmer@web.de>
Signed-off-by: rituj <ritujbeniwal@gmail.com>
Signed-off-by: althafvly <althafvly@gmail.com>
Change-Id: I585c7366cb99c0c3baf699a5a553e77da895d195
30 files changed, 1376 insertions, 422 deletions
diff --git a/packages/SystemUI/res/drawable/ic_speaker_bluetooth.xml b/packages/SystemUI/res/drawable/ic_speaker_bluetooth.xml new file mode 100644 index 000000000000..7a4b23e90483 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_speaker_bluetooth.xml @@ -0,0 +1,23 @@ +<!-- + Copyright (C) 2020 The Paranoid Android Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="24dp" + android:width="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path android:fillColor="@android:color/white" + android:pathData="M4,3A2,2 0 0,0 2,5V19A2,2 0 0,0 4,21H12A2,2 0 0,0 14,19V5A2,2 0 0,0 12,3H4M8,5A2,2 0 0,1 10,7A2,2 0 0,1 8,9A2,2 0 0,1 6,7A2,2 0 0,1 8,5M19,7V10.79L16.71,8.5L16,9.21L18.79,12L16,14.79L16.71,15.5L19,13.21V17H19.5L22.35,14.14L20.21,12L22.35,9.85L19.5,7H19M20,8.91L20.94,9.85L20,10.79V8.91M8,11A4,4 0 0,1 12,15A4,4 0 0,1 8,19A4,4 0 0,1 4,15A4,4 0 0,1 8,11M8,13A2,2 0 0,0 6,15A2,2 0 0,0 8,17A2,2 0 0,0 10,15A2,2 0 0,0 8,13M20,13.21L20.94,14.14L20,15.08V13.21Z" /> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_tick_mark_media.xml b/packages/SystemUI/res/drawable/ic_tick_mark_media.xml new file mode 100644 index 000000000000..49df1a9324b6 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_tick_mark_media.xml @@ -0,0 +1,23 @@ +<!-- + Copyright (C) 2020 The Paranoid Android Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="24dp" + android:width="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path android:fillColor="@android:color/white" + android:pathData="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z" /> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_volume_notification.xml b/packages/SystemUI/res/drawable/ic_volume_notification.xml index 42eb7b7f3f88..d56120c366ac 100644 --- a/packages/SystemUI/res/drawable/ic_volume_notification.xml +++ b/packages/SystemUI/res/drawable/ic_volume_notification.xml @@ -21,10 +21,7 @@ android:tint="?android:attr/colorControlNormal" > <path - android:fillColor="#FFFFFFFF" - android:pathData="M18,17v-6c0,-3.07 -1.63,-5.64 -4.5,-6.32V4c0,-0.83 -0.67,-1.5 -1.5,-1.5S10.5,3.17 10.5,4v0.68C7.64,5.36 6,7.92 6,11v6H4v2h10h0.38H20v-2H18zM16,17H8v-6c0,-2.48 1.51,-4.5 4,-4.5s4,2.02 4,4.5V17z"/> - <path - android:fillColor="#FFFFFFFF" - android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4C10,21.1 10.9,22 12,22z"/> + android:fillColor="#FFFFFF" + android:pathData="M20,2H4A2,2 0 0,0 2,4V22L6,18H20A2,2 0 0,0 22,16V4A2,2 0 0,0 20,2M20,16H6L4,18V4H20" /> </vector> diff --git a/packages/SystemUI/res/drawable/ic_volume_notification_mute.xml b/packages/SystemUI/res/drawable/ic_volume_notification_mute.xml index 9cb7ca3679b9..387388743767 100644 --- a/packages/SystemUI/res/drawable/ic_volume_notification_mute.xml +++ b/packages/SystemUI/res/drawable/ic_volume_notification_mute.xml @@ -21,13 +21,10 @@ android:tint="?android:attr/colorControlNormal" > <path - android:fillColor="#FFFFFFFF" - android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4C10,21.1 10.9,22 12,22z"/> + android:fillColor="#FFFFFF" + android:pathData="M2.08,21.85V5C1.41,4.36 0.74 ,3.71 0.09 ,3L1.37,1.79,22,22.39l-1.26,1.24L15.07,18H6l-3.9,3.9Zm2-14.78c-0.06 0.49 -0.06,10.65,0,10.81a1,1,0,0,0,0.16-0.12l1.64-1.64A0.46 0.46 ,0,0,1,6.29,16H13Z" /> <path - android:fillColor="#FFFFFFFF" - android:pathData="M16,16L2.81,2.81L1.39,4.22l4.85,4.85C6.09,9.68 6,10.33 6,11v6H4v2h12.17l3.61,3.61l1.41,-1.41L16,16zM8,17c0,0 0.01,-6.11 0.01,-6.16L14.17,17H8z"/> - <path - android:fillColor="#FFFFFFFF" - android:pathData="M12,6.5c2.49,0 4,2.02 4,4.5v2.17l2,2V11c0,-3.07 -1.63,-5.64 -4.5,-6.32V4c0,-0.83 -0.67,-1.5 -1.5,-1.5S10.5,3.17 10.5,4v0.68C9.72,4.86 9.05,5.2 8.46,5.63L9.93,7.1C10.51,6.73 11.2,6.5 12,6.5z"/> + android:fillColor="#FFFFFF" + android:pathData="M18.13,16h1.7A1.16,1.16,0,0,0,20,16V4.27A1.6,1.6,0,0,0,20,4H6.19v0A1.81,1.81,0,0,1,6,3.89L4.28,2.21l-0.15-0.15 0.21 ,0H19.87a2.16,2.16,0,0,1,1.35 0.43 ,1.89,1.89,0,0,1,0.71,1.13,3.68,3.68,0,0,1,0.06 0.57 V15.86a2,2,0,0,1-0.6,1.53A1.87,1.87,0,0,1,20.2,18a0.27 0.27 ,0,0,1-0.21-0.07L18.2,16.1S18.17,16,18.13,16Z" /> </vector> diff --git a/packages/SystemUI/res/drawable/rounded_ripple.xml b/packages/SystemUI/res/drawable/rounded_ripple.xml index d9ed8233d886..5851d1d7f812 100644 --- a/packages/SystemUI/res/drawable/rounded_ripple.xml +++ b/packages/SystemUI/res/drawable/rounded_ripple.xml @@ -23,7 +23,7 @@ </item> <item android:id="@android:id/background"> <shape android:shape="rectangle"> - <solid android:color="?android:attr/colorBackgroundFloating"/> + <solid android:color="@null"/> <corners android:radius="8dp"/> </shape> </item> diff --git a/packages/SystemUI/res/drawable/rounded_volume_background.xml b/packages/SystemUI/res/drawable/rounded_volume_background.xml new file mode 100644 index 000000000000..6f377cf54793 --- /dev/null +++ b/packages/SystemUI/res/drawable/rounded_volume_background.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <corners android:radius="?android:attr/dialogCornerRadius" /> + <solid android:color="?android:attr/colorBackgroundFloating" /> +</shape> diff --git a/packages/SystemUI/res/drawable/volume_dialog_seekbar.xml b/packages/SystemUI/res/drawable/volume_dialog_seekbar.xml new file mode 100644 index 000000000000..02a3c628c3de --- /dev/null +++ b/packages/SystemUI/res/drawable/volume_dialog_seekbar.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@android:id/progress"> + <clip + android:clipOrientation="horizontal" + android:gravity="left"> + <selector> + <item + android:drawable="@android:color/transparent" + android:state_enabled="false" /> + <item> + <shape android:shape="rectangle"> + <corners android:radius="?android:attr/dialogCornerRadius" /> + <size android:height="@dimen/volume_dialog_panel_width" /> + <solid android:color="?android:attr/colorAccent" /> + </shape> + </item> + </selector> + </clip> + </item> +</layer-list> diff --git a/packages/SystemUI/res/layout-land/volume_dialog.xml b/packages/SystemUI/res/layout-land/volume_dialog.xml index 5da7819c3d76..2b577399a5af 100644 --- a/packages/SystemUI/res/layout-land/volume_dialog.xml +++ b/packages/SystemUI/res/layout-land/volume_dialog.xml @@ -13,135 +13,199 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> -<FrameLayout +<LinearLayout 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:id="@+id/volume_dialog" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:gravity="right" - android:layout_gravity="right" android:background="@android:color/transparent" + android:clipChildren="false" + android:clipToPadding="false" + android:gravity="start" + android:orientation="vertical" + android:paddingBottom="@dimen/volume_dialog_panel_transparent_padding" + android:paddingLeft="@dimen/volume_dialog_panel_transparent_padding_left_right" + android:paddingRight="@dimen/volume_dialog_panel_transparent_padding_left_right" + android:paddingTop="@dimen/volume_dialog_panel_transparent_padding" android:theme="@style/qs_theme"> - <FrameLayout - android:id="@+id/volume_dialog" - android:minWidth="@dimen/volume_dialog_panel_width" + <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" - android:gravity="right" - android:layout_gravity="right" - 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" - android:clipToPadding="false"> + android:layout_marginBottom="@dimen/volume_dialog_spacer" + android:clipChildren="false" + android:gravity="start" + android:orientation="horizontal"> <FrameLayout android:id="@+id/ringer" - android:layout_width="@dimen/volume_dialog_ringer_size" - android:layout_height="@dimen/volume_dialog_ringer_size" - android:layout_marginBottom="@dimen/volume_dialog_spacer" - android:gravity="right" - android:layout_gravity="right" - android:translationZ="@dimen/volume_dialog_elevation" - android:clipToPadding="false" - android:background="@drawable/rounded_bg_full"> + android:layout_width="@dimen/volume_dialog_panel_width" + android:layout_height="@dimen/volume_dialog_panel_width" + android:layout_marginEnd="@dimen/volume_dialog_spacer" + android:background="@drawable/rounded_volume_background" + android:elevation="@dimen/volume_dialog_elevation"> + <com.android.keyguard.AlphaOptimizedImageButton android:id="@+id/ringer_icon" style="@style/VolumeButtons" - android:background="@drawable/rounded_ripple" android:layout_width="match_parent" android:layout_height="match_parent" - android:scaleType="fitCenter" - android:padding="@dimen/volume_dialog_ringer_icon_padding" - android:tint="@color/accent_tint_color_selector" - 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_marginRight="@dimen/volume_dialog_stream_padding" - android:layout_marginTop="6dp"/> + android:padding="16dp" + android:tint="?android:attr/colorAccent" /> + + <include + layout="@layout/volume_dnd_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="start" + android:layout_marginStart="6dp" + android:layout_marginTop="6dp" /> </FrameLayout> <LinearLayout - android:id="@+id/main" - android:layout_width="wrap_content" - android:minWidth="@dimen/volume_dialog_panel_width" - android:layout_height="wrap_content" - android:layout_marginTop="68dp" - android:gravity="right" - android:layout_gravity="right" + android:id="@+id/expandable_indicator_container" + android:layout_width="@dimen/volume_dialog_panel_width" + android:layout_height="@dimen/volume_dialog_panel_width" + android:layout_marginEnd="@dimen/volume_dialog_row_spacer" + android:background="@drawable/rounded_volume_background" + android:elevation="@dimen/volume_dialog_elevation" + android:gravity="center_vertical" + android:orientation="horizontal"> + + <com.android.systemui.statusbar.phone.ExpandableIndicator + android:id="@+id/expandable_indicator" + style="@style/VolumeButtons" + android:layout_width="@dimen/volume_dialog_panel_width" + android:layout_height="match_parent" + android:contentDescription="@string/accessibility_quick_settings_expand" + android:rotation="90" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/media_button_view" + android:layout_width="@dimen/volume_dialog_panel_width" + android:layout_height="@dimen/volume_dialog_panel_width" + android:layout_marginEnd="@dimen/volume_dialog_spacer" + android:background="@drawable/rounded_volume_background" + android:elevation="@dimen/volume_dialog_elevation" android:orientation="vertical" - android:translationZ="@dimen/volume_dialog_elevation" - android:clipChildren="false" - android:clipToPadding="false" - android:background="@drawable/rounded_bg_full" > + android:visibility="gone"> + + <com.android.keyguard.AlphaOptimizedImageButton + android:id="@+id/media_button" + style="@style/VolumeButtons" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:padding="13dp" + android:src="@drawable/ic_speaker_bluetooth" /> + </LinearLayout> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="@dimen/volume_dialog_panel_width" + android:gravity="center_vertical" + android:orientation="horizontal"> + <LinearLayout - android:id="@+id/volume_dialog_rows" + android:id="@+id/odi_captions" 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"> - <!-- volume rows added and removed here! :-) --> + android:layout_height="match_parent" + android:background="@drawable/rounded_volume_background" + android:elevation="@dimen/volume_dialog_elevation" + android:orientation="vertical" + android:visibility="gone"> + + <com.android.systemui.volume.CaptionsToggleImageButton + android:id="@+id/odi_captions_icon" + style="@style/VolumeButtons" + android:layout_width="@dimen/volume_dialog_panel_width" + android:layout_height="match_parent" + android:src="@drawable/ic_volume_odi_captions_disabled" + sysui:optedOut="false" /> </LinearLayout> - <FrameLayout - android:id="@+id/settings_container" - android:layout_width="match_parent" + + <ViewStub + android:id="@+id/odi_captions_tooltip_stub" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:background="@drawable/rounded_bg_bottom_background"> - <com.android.keyguard.AlphaOptimizedImageButton - android:id="@+id/settings" - android:src="@drawable/ic_tune_black_16dp" - android:layout_width="@dimen/volume_dialog_tap_target_size" - android:layout_height="@dimen/volume_dialog_tap_target_size" - android:layout_gravity="center" - android:contentDescription="@string/accessibility_volume_settings" - android:background="@drawable/ripple_drawable_20dp" - android:tint="?android:attr/textColorSecondary" - android:soundEffectsEnabled="false" /> - </FrameLayout> + android:layout_marginStart="@dimen/volume_dialog_spacer" + android:inflatedId="@+id/odi_captions_tooltip_view" + android:layout="@layout/volume_tool_tip_view" /> </LinearLayout> + </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_marginRight="68dp" - android:gravity="right" - android:layout_gravity="right" - android:clipToPadding="false" - android:translationZ="@dimen/volume_dialog_elevation" - android:background="@drawable/rounded_bg_full"> - <com.android.systemui.volume.CaptionsToggleImageButton - android:id="@+id/odi_captions_icon" - android:src="@drawable/ic_volume_odi_captions_disabled" - 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> + <FrameLayout + android:layout_width="wrap_content" + android:layout_height="@dimen/volume_dialog_slider_height" + android:layout_marginTop="@dimen/volume_dialog_spacer" + android:clipChildren="false" + android:clipToPadding="false"> - <ViewStub - android:id="@+id/odi_captions_tooltip_stub" - android:inflatedId="@+id/odi_captions_tooltip_view" - android:layout="@layout/volume_tool_tip_view" + <LinearLayout + android:id="@+id/volume_dialog_rows" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginRight="@dimen/volume_tool_tip_right_margin" - android:layout_marginTop="@dimen/volume_tool_tip_top_margin" - android:layout_gravity="right"/> + android:clipChildren="false" + android:clipToPadding="false" + android:gravity="center" + android:minWidth="@dimen/volume_dialog_panel_width" + android:orientation="horizontal"> + <!-- volume rows added and removed here! :-) --> + </LinearLayout> - </FrameLayout> + <LinearLayout + android:id="@+id/media_output_scroller" + android:layout_width="@dimen/volume_dialog_media_width" + android:layout_height="match_parent" + android:background="@drawable/rounded_volume_background" + android:clipChildren="false" + android:clipToPadding="false" + android:elevation="@dimen/volume_dialog_elevation" + android:orientation="vertical" + android:visibility="gone"> + + <com.android.systemui.statusbar.AlphaOptimizedTextView + android:id="@+id/media_output_title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="end" + android:clickable="false" + android:ellipsize="marquee" + android:focusable="true" + android:marqueeRepeatLimit="marquee_forever" + android:paddingBottom="5dp" + android:paddingLeft="8dp" + android:paddingRight="6dp" + android:paddingTop="5dp" + android:singleLine="true" + android:text="@string/media_output_title" + android:textColor="?android:attr/colorControlNormal" + android:textSize="15sp" + android:textStyle="bold" /> -</FrameLayout>
\ No newline at end of file + <View + android:layout_width="match_parent" + android:layout_height="2dp" + android:background="@color/divider_stroke_color" /> + + <ScrollView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:fillViewport="true" + android:scrollbars="none"> + + <LinearLayout + android:id="@+id/media_output_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="top" + android:gravity="top" + android:layoutDirection="rtl" + android:orientation="vertical"> + <!-- media output devices added and removed here --> + </LinearLayout> + </ScrollView> + </LinearLayout> + </FrameLayout> +</LinearLayout> diff --git a/packages/SystemUI/res/layout-land/volume_tool_tip_view.xml b/packages/SystemUI/res/layout-land/volume_tool_tip_view.xml new file mode 100644 index 000000000000..3af2b789fcac --- /dev/null +++ b/packages/SystemUI/res/layout-land/volume_tool_tip_view.xml @@ -0,0 +1,64 @@ +<?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 + --> + +<com.android.systemui.volume.VolumeToolTipView + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/tooltip_view" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:gravity="center_vertical" + android:orientation="horizontal"> + + <View + android:id="@+id/arrow" + android:layout_width="@dimen/volume_tool_tip_arrow_width" + android:layout_height="@dimen/volume_tool_tip_arrow_height" + android:layout_marginEnd="@dimen/volume_tool_tip_arrow_margin_container" /> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingEnd="4dp" + android:paddingStart="16dp" + android:background="@drawable/volume_tool_tip_rounded_bg" + android:orientation="horizontal"> + + <TextView + android:id="@+id/text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:text="@string/volume_odi_captions_tip" + android:textColor="@android:color/white" + android:textSize="14sp" /> + + <ImageView + android:id="@+id/dismiss" + android:layout_width="40dp" + android:layout_height="40dp" + android:layout_gravity="center_vertical" + android:padding="12dp" + android:layout_marginStart="2dp" + android:layout_marginEnd="2dp" + android:alpha="0.7" + android:src="@drawable/ic_remove_no_shadow" + android:tint="@android:color/white" + android:background="?android:attr/selectableItemBackgroundBorderless" + android:contentDescription="@string/accessibility_volume_close_odi_captions_tip"/> + </LinearLayout> + +</com.android.systemui.volume.VolumeToolTipView> diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml index 2296b613d56c..32440e14ffbc 100644 --- a/packages/SystemUI/res/layout/volume_dialog.xml +++ b/packages/SystemUI/res/layout/volume_dialog.xml @@ -13,131 +13,214 @@ See the License for the specific language governing permissions and limitations under the License. --> -<FrameLayout +<LinearLayout 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:id="@+id/volume_dialog" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:gravity="right" - android:layout_gravity="right" android:background="@android:color/transparent" + android:clipChildren="false" + android:clipToPadding="false" + android:orientation="vertical" + android:paddingBottom="@dimen/volume_dialog_panel_transparent_padding" + android:paddingLeft="@dimen/volume_dialog_panel_transparent_padding_left_right" + android:paddingRight="@dimen/volume_dialog_panel_transparent_padding_left_right" + android:paddingTop="@dimen/volume_dialog_panel_transparent_padding" android:theme="@style/qs_theme"> - <!-- right-aligned to be physically near volume button --> <LinearLayout - android:id="@+id/volume_dialog" - android:minWidth="@dimen/volume_dialog_panel_width" android:layout_width="wrap_content" 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" - android:orientation="vertical" - android:clipToPadding="false"> + android:clipToPadding="false" + android:clipChildren="false" + android:orientation="horizontal"> <FrameLayout android:id="@+id/ringer" - android:layout_width="@dimen/volume_dialog_ringer_size" - android:layout_height="@dimen/volume_dialog_ringer_size" - android:layout_marginBottom="@dimen/volume_dialog_spacer" - android:translationZ="@dimen/volume_dialog_elevation" - android:clipToPadding="false" - android:background="@drawable/rounded_bg_full"> + android:layout_width="@dimen/volume_dialog_panel_width" + android:layout_height="@dimen/volume_dialog_panel_width" + android:background="@drawable/rounded_volume_background" + android:elevation="@dimen/volume_dialog_elevation"> + <com.android.keyguard.AlphaOptimizedImageButton android:id="@+id/ringer_icon" style="@style/VolumeButtons" - android:background="@drawable/rounded_ripple" android:layout_width="match_parent" android:layout_height="match_parent" - android:scaleType="fitCenter" - android:padding="@dimen/volume_dialog_ringer_icon_padding" - android:tint="@color/accent_tint_color_selector" - 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"/> + android:padding="16dp" + android:tint="?android:attr/colorAccent" /> + + <include + layout="@layout/volume_dnd_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="start" + android:layout_marginStart="6dp" + android:layout_marginTop="6dp" /> </FrameLayout> + </LinearLayout> + + <FrameLayout + android:layout_width="wrap_content" + android:layout_height="@dimen/volume_dialog_slider_height" + android:layout_marginTop="@dimen/volume_dialog_spacer" + android:clipChildren="false" + android:clipToPadding="false"> <LinearLayout - android:id="@+id/main" - android:minWidth="@dimen/volume_dialog_panel_width" + android:id="@+id/volume_dialog_rows" 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_full" > - <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"> - <!-- volume rows added and removed here! :-) --> - </LinearLayout> - <FrameLayout - android:id="@+id/settings_container" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:background="@drawable/rounded_bg_bottom_background"> - <com.android.keyguard.AlphaOptimizedImageButton - android:id="@+id/settings" - android:src="@drawable/ic_tune_black_16dp" - android:layout_width="@dimen/volume_dialog_tap_target_size" - android:layout_height="@dimen/volume_dialog_tap_target_size" - android:layout_gravity="center" - android:contentDescription="@string/accessibility_volume_settings" - android:background="@drawable/ripple_drawable_20dp" - android:tint="?android:attr/textColorSecondary" - android:soundEffectsEnabled="false" /> - </FrameLayout> + android:gravity="center" + android:minWidth="@dimen/volume_dialog_panel_width" + android:orientation="horizontal"> + <!-- volume rows added and removed here! :-) --> </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" + <LinearLayout + android:id="@+id/media_output_scroller" + android:layout_width="@dimen/volume_dialog_media_width" + android:layout_height="match_parent" + android:background="@drawable/rounded_volume_background" + android:clickable="false" + android:clipChildren="false" android:clipToPadding="false" - android:translationZ="@dimen/volume_dialog_elevation" - android:background="@drawable/rounded_bg_full"> - <com.android.systemui.volume.CaptionsToggleImageButton - android:id="@+id/odi_captions_icon" - android:src="@drawable/ic_volume_odi_captions_disabled" - style="@style/VolumeButtons" - android:background="@drawable/rounded_ripple" + android:elevation="@dimen/volume_dialog_elevation" + android:orientation="vertical" + android:visibility="gone"> + + <com.android.systemui.statusbar.AlphaOptimizedTextView + android:id="@+id/media_output_title" 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> + android:layout_height="wrap_content" + android:layout_gravity="end" + android:clickable="false" + android:ellipsize="marquee" + android:focusable="true" + android:marqueeRepeatLimit="marquee_forever" + android:paddingBottom="5dp" + android:paddingLeft="8dp" + android:paddingRight="6dp" + android:paddingTop="5dp" + android:singleLine="true" + android:text="@string/media_output_title" + android:textColor="?android:attr/colorControlNormal" + android:textSize="15sp" + android:textStyle="bold" /> - </LinearLayout> + <View + android:layout_width="match_parent" + android:layout_height="2dp" + android:background="@color/divider_stroke_color" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:orientation="horizontal"> + + <ScrollView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:fillViewport="true" + android:scrollbars="none"> - <ViewStub - android:id="@+id/odi_captions_tooltip_stub" - android:inflatedId="@+id/odi_captions_tooltip_view" - android:layout="@layout/volume_tool_tip_view" + <LinearLayout + android:id="@+id/media_output_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="top" + android:gravity="top" + android:layoutDirection="rtl" + android:orientation="vertical"> + <!-- media output devices added and removed here --> + </LinearLayout> + </ScrollView> + </LinearLayout> + </LinearLayout> + </FrameLayout> + + <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="bottom | right" - android:layout_marginRight="@dimen/volume_tool_tip_right_margin" - android:layout_marginBottom="@dimen/volume_tool_tip_bottom_margin"/> + android:clipChildren="false" + android:layout_marginTop="@dimen/volume_dialog_spacer" + android:minWidth="@dimen/volume_dialog_panel_width" + android:orientation="horizontal"> + + <LinearLayout + android:id="@+id/expandable_indicator_container" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/volume_dialog_spacer" + android:background="@drawable/rounded_volume_background" + android:elevation="@dimen/volume_dialog_elevation" + android:orientation="vertical"> + + <com.android.systemui.statusbar.phone.ExpandableIndicator + android:id="@+id/expandable_indicator" + style="@style/VolumeButtons" + android:layout_width="@dimen/volume_dialog_panel_width" + android:layout_height="@dimen/volume_dialog_button_height" + android:background="@drawable/ripple_drawable_20dp" + android:rotation="90" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/media_button_view" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/volume_dialog_spacer" + android:background="@drawable/rounded_volume_background" + android:elevation="@dimen/volume_dialog_elevation" + android:orientation="vertical" + android:visibility="gone"> + + <com.android.keyguard.AlphaOptimizedImageButton + android:id="@+id/media_button" + style="@style/VolumeButtons" + android:layout_width="@dimen/volume_dialog_panel_width" + android:layout_height="@dimen/volume_dialog_button_height" + android:background="@drawable/ripple_drawable_20dp" + android:padding="10dp" + android:src="@drawable/ic_speaker_bluetooth" /> + </LinearLayout> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="start" + android:orientation="vertical"> + + <LinearLayout + android:id="@+id/odi_captions" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="@drawable/rounded_volume_background" + android:elevation="@dimen/volume_dialog_elevation" + android:orientation="vertical" + android:visibility="gone"> + + <com.android.systemui.volume.CaptionsToggleImageButton + android:id="@+id/odi_captions_icon" + style="@style/VolumeButtons" + android:layout_width="@dimen/volume_dialog_panel_width" + android:layout_height="@dimen/volume_dialog_button_height" + android:background="@drawable/ripple_drawable_20dp" + android:src="@drawable/ic_volume_odi_captions_disabled" + sysui:optedOut="false" /> + </LinearLayout> -</FrameLayout>
\ No newline at end of file + <ViewStub + android:id="@+id/odi_captions_tooltip_stub" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/volume_dialog_spacer" + android:inflatedId="@+id/odi_captions_tooltip_view" + android:layout="@layout/volume_tool_tip_view" /> + </LinearLayout> + </LinearLayout> +</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/volume_dialog_media_output.xml b/packages/SystemUI/res/layout/volume_dialog_media_output.xml new file mode 100644 index 000000000000..30490d06dfd6 --- /dev/null +++ b/packages/SystemUI/res/layout/volume_dialog_media_output.xml @@ -0,0 +1,93 @@ +<!-- + Copyright (C) 2020 The AOSPA-Extended Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="4dp" + android:layout_gravity="end|top" + android:gravity="end" + android:background="@drawable/rounded_ripple" + android:clickable="true" + android:orientation="horizontal" + android:theme="@style/qs_theme"> + + <com.android.systemui.statusbar.AlphaOptimizedImageView + android:id="@+id/media_output_selected" + android:layout_width="30dp" + android:layout_height="30dp" + android:layout_gravity="start|center_vertical" + android:gravity="center" + android:src="@drawable/ic_tick_mark_media" + android:padding="6dp" + android:scaleType="fitCenter" + android:clickable="false" + android:tint="?android:attr/colorControlNormal" + android:soundEffectsEnabled="false" + android:visibility="gone" /> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_gravity="end|center_vertical" + android:layout_weight="1" + android:gravity="end" + android:paddingLeft="4dp" + android:paddingRight="4dp" + android:clickable="false" + android:orientation="vertical"> + <com.android.systemui.statusbar.AlphaOptimizedTextView + android:id="@+id/media_output_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="end" + android:gravity="left" + android:clickable="false" + android:ellipsize="marquee" + android:marqueeRepeatLimit="marquee_forever" + android:focusable="true" + android:singleLine="true" + android:textSize="14sp" + android:textStyle="bold" + android:textColor="?android:attr/colorControlNormal" /> + <com.android.systemui.statusbar.AlphaOptimizedTextView + android:id="@+id/media_output_summary" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="end" + android:gravity="left" + android:ellipsize="marquee" + android:clickable="false" + android:marqueeRepeatLimit="marquee_forever" + android:focusable="true" + android:layout_marginTop="-2dp" + android:singleLine="true" + android:textSize="11sp" + android:textStyle="italic" + android:textColor="?android:attr/colorControlNormal" + android:visibility="gone" /> + </LinearLayout> + + <com.android.systemui.statusbar.AlphaOptimizedImageView + android:id="@+id/media_output_icon" + android:layout_width="32dp" + android:layout_height="32dp" + android:layout_gravity="end|center_vertical" + android:gravity="left" + android:padding="2dp" + android:clickable="false" + android:scaleType="fitCenter" + android:soundEffectsEnabled="false"/> +</LinearLayout> diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml index 6128da8627a9..aa9c403f47ad 100644 --- a/packages/SystemUI/res/layout/volume_dialog_row.xml +++ b/packages/SystemUI/res/layout/volume_dialog_row.xml @@ -17,55 +17,73 @@ 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" + android:layout_width="wrap_content" + android:layout_marginEnd="@dimen/volume_dialog_row_spacer" + android:background="@drawable/rounded_volume_background" + android:elevation="@dimen/volume_dialog_elevation" android:theme="@style/qs_theme"> - <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" + <FrameLayout + android:id="@+id/volume_row_slider_frame" + android:layout_width="@dimen/volume_dialog_panel_width" + android:layout_height="@dimen/volume_dialog_slider_height"> + + <SeekBar + android:id="@+id/volume_row_slider" + android:layout_width="@dimen/volume_dialog_slider_height" + android:layout_height="@dimen/volume_dialog_panel_width" + android:layout_gravity="center" + android:background="@null" + android:clickable="true" 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:layoutDirection="rtl" - android:layout_gravity="center" - android:rotation="90" /> - </FrameLayout> + android:paddingBottom="0dp" + android:paddingEnd="0dp" + android:paddingStart="0dp" + android:paddingTop="0dp" + android:progressDrawable="@drawable/volume_dialog_seekbar" + android:rotation="90" + android:thumb="@android:color/transparent" /> - <com.android.keyguard.AlphaOptimizedImageButton - android:id="@+id/volume_row_icon" - style="@style/VolumeButtons" - 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:tint="@color/accent_tint_color_selector" - android:soundEffectsEnabled="false" /> - </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom|center_horizontal" + android:orientation="vertical"> + + <com.android.systemui.statusbar.AlphaOptimizedImageView + android:id="@+id/volume_row_icon" + android:layout_width="@dimen/volume_dialog_row_icon_size" + android:layout_height="@dimen/volume_dialog_tap_target_size" + android:layout_gravity="center_horizontal" + android:layout_marginBottom="-12dp" + android:clickable="false" + android:layoutDirection="ltr" + android:scaleType="fitCenter" + android:soundEffectsEnabled="false" + android:tint="?android:attr/colorAccent" /> - <include layout="@layout/volume_dnd_icon"/> + <com.android.systemui.statusbar.AlphaOptimizedTextView + android:id="@+id/volume_row_header" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom|center_horizontal" + android:layout_marginBottom="10dp" + android:ellipsize="end" + android:gravity="bottom|center_horizontal" + android:layoutDirection="ltr" + android:maxLength="10" + android:maxLines="1" + android:textAppearance="@style/TextAppearance.Volume.Header" + android:textColor="?android:attr/colorAccent" + android:textStyle="bold" /> + </LinearLayout> + </FrameLayout> + <include + layout="@layout/volume_dnd_icon" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="start" + android:layout_marginStart="6dp" + android:layout_marginTop="6dp" /> </FrameLayout> diff --git a/packages/SystemUI/res/layout/volume_dnd_icon.xml b/packages/SystemUI/res/layout/volume_dnd_icon.xml index 10c1472ae993..1adfb316ac59 100644 --- a/packages/SystemUI/res/layout/volume_dnd_icon.xml +++ b/packages/SystemUI/res/layout/volume_dnd_icon.xml @@ -16,14 +16,13 @@ <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/dnd_icon" - android:layout_width="match_parent" + android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="6dp"> <ImageView android:layout_width="14dp" android:layout_height="14dp" - android:layout_gravity="right|top" android:src="@*android:drawable/ic_qs_dnd" android:tint="?android:attr/textColorTertiary"/> </FrameLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/volume_tool_tip_view.xml b/packages/SystemUI/res/layout/volume_tool_tip_view.xml index 9fe885ebefc7..8de18821ad97 100644 --- a/packages/SystemUI/res/layout/volume_tool_tip_view.xml +++ b/packages/SystemUI/res/layout/volume_tool_tip_view.xml @@ -20,13 +20,20 @@ android:id="@+id/tooltip_view" android:layout_height="wrap_content" android:layout_width="wrap_content" - android:orientation="horizontal"> + android:orientation="vertical"> + + <View + android:id="@+id/arrow" + android:layout_width="@dimen/volume_tool_tip_arrow_width" + android:layout_height="@dimen/volume_tool_tip_arrow_height" + android:layout_marginBottom="@dimen/volume_tool_tip_arrow_margin_container" + android:layout_marginStart="@dimen/volume_tool_tip_arrow_margin_start"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" - android:paddingStart="16dp" android:paddingEnd="4dp" + android:paddingStart="16dp" android:background="@drawable/volume_tool_tip_rounded_bg" android:orientation="horizontal"> @@ -35,9 +42,10 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" - android:textColor="@android:color/white" android:text="@string/volume_odi_captions_tip" - android:textSize="14sp"/> + android:textColor="@android:color/white" + android:textSize="14sp" /> + <ImageView android:id="@+id/dismiss" android:layout_width="40dp" @@ -53,11 +61,4 @@ android:contentDescription="@string/accessibility_volume_close_odi_captions_tip"/> </LinearLayout> - <View - android:id="@+id/arrow" - android:layout_width="8dp" - android:layout_height="10dp" - android:layout_marginLeft="-2dp" - android:layout_gravity="center_vertical"/> - </com.android.systemui.volume.VolumeToolTipView>
\ No newline at end of file diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 7b6ad6bd7b52..4138a7672bf2 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -1098,6 +1098,7 @@ <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (déconnecté)"</string> <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Impossible de se connecter. Réessayez."</string> <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un nouvel appareil"</string> + <string name="media_output_title" msgid="115223550977351699">"Diffuser des contenus multimédias sur"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Un problème est survenu au niveau de la lecture de votre outil de mesure de batterie"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Appuyer pour en savoir plus"</string> </resources> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 91488fa7094f..55e1d897a39f 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -1098,6 +1098,7 @@ <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>(未接続)"</string> <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"接続できませんでした。もう一度お試しください。"</string> <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"新しいデバイスとのペア設定"</string> + <string name="media_output_title" msgid="115223550977351699">"メディアの再生先"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"電池残量の読み込み中に問題が発生しました"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"タップすると詳細が表示されます"</string> </resources> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index f5aadc85eab4..1b8cb2286dc9 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -1098,6 +1098,7 @@ <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>(연결 끊김)"</string> <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"연결할 수 없습니다. 다시 시도하세요."</string> <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"새 기기와 페어링"</string> + <string name="media_output_title" msgid="115223550977351699">"미디어 출력 대상"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"배터리 수준을 읽는 중에 문제가 발생함"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"탭하여 자세한 정보를 확인하세요."</string> </resources> diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml index 531b2d4a3114..254256719192 100644 --- a/packages/SystemUI/res/values-land/dimens.xml +++ b/packages/SystemUI/res/values-land/dimens.xml @@ -33,8 +33,7 @@ <integer name="quick_settings_num_columns">4</integer> <dimen name="qs_detail_margin_top">0dp</dimen> - <dimen name="volume_tool_tip_right_margin">136dp</dimen> - <dimen name="volume_tool_tip_top_margin">12dp</dimen> + <dimen name="volume_dialog_icon_padding">17dp</dimen> <!-- Padding between status bar and bubbles when displayed in expanded state, smaller value in landscape since we have limited vertical space--> diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml index b956956aa1ab..f7a85973ca7a 100644 --- a/packages/SystemUI/res/values-night/colors.xml +++ b/packages/SystemUI/res/values-night/colors.xml @@ -105,4 +105,7 @@ <!-- Color of background circle of user avatars in quick settings user switcher --> <color name="qs_user_switcher_avatar_background">#3C4043</color> + <color name="volume_background_tint">#141414</color> + <color name="divider_stroke_color">#434343</color> + </resources> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 405cbdb22a48..bf08ddb45481 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -1110,6 +1110,7 @@ <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (отключено)"</string> <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Не удалось подключиться. Повторите попытку."</string> <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Подключить новое устройство"</string> + <string name="media_output_title" msgid="115223550977351699">"Где воспроизводить"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Не удается получить данные об уровне заряда батареи"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Нажмите, чтобы узнать больше."</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index b42c89d30634..0382cb3fa64a 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -1098,6 +1098,7 @@ <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>(已断开连接)"</string> <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"无法连接。请重试。"</string> <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"与新设备配对"</string> + <string name="media_output_title" msgid="115223550977351699">"媒体播放到"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"读取电池计量器时出现问题"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"点按即可了解详情"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index a1e7054c9faa..4f0cf4c5f8f5 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -1098,6 +1098,7 @@ <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (已中斷連線)"</string> <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"無法連線,請再試一次。"</string> <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string> + <string name="media_output_title" msgid="115223550977351699">"播放媒體的裝置"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"讀取電池計量器時發生問題"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"輕按即可瞭解詳情"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index ed114c488fff..fe08028f4042 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -1098,6 +1098,7 @@ <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (已中斷連線)"</string> <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"無法連線,請再試一次。"</string> <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string> + <string name="media_output_title" msgid="115223550977351699">"播放媒體"</string> <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"讀取電池計量器時發生問題"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"輕觸即可瞭解詳情"</string> </resources> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 461fe2f9d4d2..ae177dfd59ad 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -271,4 +271,7 @@ <color name="misalignment_text_color">#F28B82</color> <color name="screenrecord_status_color">#E94235</color> + + <color name="volume_background_tint">#f2f2f2</color> + <color name="divider_stroke_color">#E0E0E0</color> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index ed72e8ba02a0..ae697fd6720b 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -439,37 +439,33 @@ <dimen name="qs_panel_width">@dimen/notification_panel_width</dimen> <dimen name="volume_dialog_panel_transparent_padding_right">4dp</dimen> - - <dimen name="volume_dialog_panel_transparent_padding">20dp</dimen> - + <dimen name="volume_dialog_panel_transparent_padding_left_right">8dp</dimen> <dimen name="volume_dialog_stream_padding">8dp</dimen> - - <dimen name="volume_dialog_panel_width">64dp</dimen> - - <dimen name="volume_dialog_slider_height">116dp</dimen> - + <dimen name="volume_tool_tip_top_margin">12dp</dimen> <dimen name="volume_dialog_ringer_size">64dp</dimen> - <dimen name="volume_dialog_ringer_icon_padding">20dp</dimen> - <dimen name="volume_dialog_caption_size">64dp</dimen> - - <dimen name="volume_dialog_tap_target_size">48dp</dimen> - + <dimen name="volume_dialog_panel_transparent_padding">20dp</dimen> + <dimen name="volume_dialog_panel_width">54dp</dimen> + <dimen name="volume_dialog_slider_height">185dp</dimen> + <dimen name="volume_dialog_icon_padding">13dp</dimen> + <dimen name="volume_dialog_tap_target_size">@dimen/volume_dialog_panel_width</dimen> + <dimen name="volume_dialog_media_width">170dp</dimen> <dimen name="volume_dialog_spacer">4dp</dimen> - - <dimen name="volume_dialog_slider_margin_top">14dp</dimen> - - <dimen name="volume_dialog_slider_margin_bottom">-2dp</dimen> - + <dimen name="volume_dialog_button_height">45dp</dimen> + <dimen name="volume_dialog_row_icon_size">24dp</dimen> + <dimen name="volume_dialog_row_spacer">@dimen/volume_dialog_spacer</dimen> <dimen name="volume_dialog_row_margin_bottom">8dp</dimen> - <dimen name="volume_dialog_elevation">9dp</dimen> + <dimen name="volume_dialog_slider_margin_top">14dp</dimen> + <dimen name="volume_dialog_slider_margin_bottom">-2dp</dimen> <dimen name="volume_tool_tip_right_margin">76dp</dimen> - <dimen name="volume_tool_tip_bottom_margin">32dp</dimen> - + <dimen name="volume_tool_tip_arrow_height">8dp</dimen> + <dimen name="volume_tool_tip_arrow_width">10dp</dimen> + <dimen name="volume_tool_tip_arrow_margin_container">-2dp</dimen> + <dimen name="volume_tool_tip_arrow_margin_start">24dp</dimen> <dimen name="volume_tool_tip_arrow_corner_radius">2dp</dimen> <!-- Gravity for the notification panel --> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 3d08c6680319..d7183d73caad 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1059,6 +1059,9 @@ <!-- Description of the left direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] --> <string name="description_direction_left">"Slide left for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string> + <!-- Title for media output settings --> + <string name="media_output_title">Play media to</string> + <!-- Zen mode: Priority only introduction message on first use --> <string name="zen_priority_introduction">You won\'t be disturbed by sounds and vibrations, except from alarms, reminders, events, and callers you specify. You\'ll still hear anything you choose to play including music, videos, and games.</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 1c0518208dea..787b6e9e01cf 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -488,7 +488,14 @@ </style> <style name="VolumeButtons" parent="@android:style/Widget.Material.Button.Borderless"> - <item name="android:background">@drawable/btn_borderless_rect</item> + <item name="android:layout_gravity">center</item> + <item name="android:background">@drawable/rounded_ripple</item> + <item name="android:clickable">true</item> + <item name="android:focusable">true</item> + <item name="android:padding">@dimen/volume_dialog_icon_padding</item> + <item name="android:scaleType">fitCenter</item> + <item name="android:soundEffectsEnabled">false</item> + <item name="android:tint">?android:attr/colorControlNormal</item> </style> <style name="DockedDividerBackground"> diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java index c128cdf8a9c0..aa18d1b62b44 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java @@ -543,6 +543,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa updateRingerModeExternalW(mRingerModeObservers.mRingerMode.getValue()); updateZenModeW(); updateZenConfig(); + updateLinkNotificationConfigW(); updateEffectsSuppressorW(mNoMan.getEffectsSuppressor()); mCallbacks.onStateChanged(mState); } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 587b10480708..74605da708d7 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -23,16 +23,18 @@ 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_NOTIFICATION; 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.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED; +import android.animation.Animator; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.app.ActivityManager; @@ -50,6 +52,7 @@ import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.media.AudioSystem; import android.os.Debug; @@ -70,9 +73,13 @@ import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.View.AccessibilityDelegate; +import android.view.ViewAnimationUtils; 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; @@ -81,12 +88,18 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; import android.widget.ImageButton; +import android.widget.ImageView; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import android.widget.Toast; import com.android.settingslib.Utils; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.media.InfoMediaManager; +import com.android.settingslib.media.LocalMediaManager; +import com.android.settingslib.media.MediaDevice; +import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.Dependency; import com.android.systemui.Prefs; import com.android.systemui.R; @@ -96,6 +109,7 @@ import com.android.systemui.plugins.VolumeDialog; import com.android.systemui.plugins.VolumeDialogController; import com.android.systemui.plugins.VolumeDialogController.State; import com.android.systemui.plugins.VolumeDialogController.StreamState; +import com.android.systemui.statusbar.phone.ExpandableIndicator; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -112,7 +126,7 @@ import java.util.List; * Methods ending in "H" must be called on the (ui) handler. */ public class VolumeDialogImpl implements VolumeDialog, - ConfigurationController.ConfigurationListener { + ConfigurationController.ConfigurationListener, LocalMediaManager.DeviceCallback { private static final String TAG = Util.logTag(VolumeDialogImpl.class); private static final long USER_ATTEMPT_GRACE_PERIOD = 1000; @@ -125,6 +139,11 @@ public class VolumeDialogImpl implements VolumeDialog, static final int DIALOG_SHOW_ANIMATION_DURATION = 300; static final int DIALOG_HIDE_ANIMATION_DURATION = 250; + private static final int SLIDER_PROGRESS_ALPHA_ACTIVE = 100; + private static final int SLIDER_PROGRESS_ALPHA_ACTIVE_DARK = 60; + private static final int SLIDER_PROGRESS_ALPHA = 50; + private static final int SLIDER_PROGRESS_ALPHA_DARK = 40; + private final Context mContext; private final H mHandler = new H(); private final VolumeDialogController mController; @@ -135,11 +154,16 @@ public class VolumeDialogImpl implements VolumeDialog, private ViewGroup mDialogView; private ViewGroup mDialogRowsView; private ViewGroup mRinger; + private ViewGroup mMediaOutputView; + private ViewGroup mMediaOutputScrollView; + private ViewGroup mMediaButtonView; + private TextView mMediaTitleText; + private ImageButton mMediaButton; private ImageButton mRingerIcon; private ViewGroup mODICaptionsView; private CaptionsToggleImageButton mODICaptionsIcon; - private View mSettingsView; - private ImageButton mSettingsIcon; + private View mExpandRowsView; + private ExpandableIndicator mExpandRows; private FrameLayout mZenIcon; private final List<VolumeRow> mRows = new ArrayList<>(); private ConfigurableTexts mConfigurableTexts; @@ -163,12 +187,28 @@ public class VolumeDialogImpl implements VolumeDialog, private boolean mShowActiveStreamOnly; private boolean mConfigChanged = false; private boolean mIsAnimatingDismiss = false; + private boolean mODIServiceComponentEnabled; + private boolean mPendingOdiCaptionsTooltip; private boolean mHasSeenODICaptionsTooltip; private ViewStub mODICaptionsTooltipViewStub; private View mODICaptionsTooltipView = null; private boolean mHasAlertSlider; private boolean mLeftVolumeRocker; + private LocalMediaManager mLocalMediaManager; + private Animator mCurrAnimator; + + private boolean mDarkMode; + private boolean mVibrateOnSlider; + + private boolean mExpanded; + private boolean mShowingMediaDevices; + + private float mElevation; + private float mHeight, mWidth, mSpacer; + + private final List<MediaOutputRow> mMediaOutputRows = new ArrayList<>(); + public VolumeDialogImpl(Context context) { mContext = new ContextThemeWrapper(context, R.style.qs_theme); @@ -182,11 +222,33 @@ public class VolumeDialogImpl implements VolumeDialog, Prefs.getBoolean(context, Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, false); mHasAlertSlider = mContext.getResources().getBoolean(com.android.internal.R.bool.config_hasAlertSlider); mLeftVolumeRocker = mContext.getResources().getBoolean(R.bool.config_audioPanelOnLeftSide); + mVibrateOnSlider = mContext.getResources().getBoolean(R.bool.config_vibrateOnIconAnimation); + mElevation = mContext.getResources().getDimension(R.dimen.volume_dialog_elevation); + mSpacer = mContext.getResources().getDimension(R.dimen.volume_dialog_row_spacer); + + setDarkMode(); } @Override public void onUiModeChanged() { mContext.getTheme().applyStyle(mContext.getThemeResId(), true); + removeAllMediaOutputRows(); + setDarkMode(); + } + + private void setDarkMode() { + final int nightModeFlag = mContext.getResources().getConfiguration().uiMode & + Configuration.UI_MODE_NIGHT_MASK; + + switch (nightModeFlag) { + case Configuration.UI_MODE_NIGHT_YES: + mDarkMode = true; + break; + case Configuration.UI_MODE_NIGHT_NO: + case Configuration.UI_MODE_NIGHT_UNDEFINED: + mDarkMode = false; + break; + } } public void init(int windowType, Callback callback) { @@ -205,16 +267,20 @@ public class VolumeDialogImpl implements VolumeDialog, mController.removeCallback(mControllerCallbackH); mHandler.removeCallbacksAndMessages(null); Dependency.get(ConfigurationController.class).removeCallback(this); + if (mLocalMediaManager != null) { + mLocalMediaManager.unregisterCallback(this); + } } private void initDialog() { mDialog = new CustomDialog(mContext); - mConfigurableTexts = new ConfigurableTexts(mContext); mHovering = false; mShowing = false; + mExpanded = false; mWindow = mDialog.getWindow(); mWindow.requestFeature(Window.FEATURE_NO_TITLE); + mWindow.getDecorView(); mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR); @@ -225,24 +291,44 @@ public class VolumeDialogImpl implements VolumeDialog, | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); mWindow.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY); mWindow.setWindowAnimations(com.android.internal.R.style.Animation_Toast); - WindowManager.LayoutParams lp = mWindow.getAttributes(); + final WindowManager.LayoutParams lp = mWindow.getAttributes(); lp.format = PixelFormat.TRANSLUCENT; - lp.setTitle(VolumeDialogImpl.class.getSimpleName()); - lp.windowAnimations = -1; + lp.width = MATCH_PARENT; + lp.height = WRAP_CONTENT; if(!isAudioPanelOnLeftSide()){ lp.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL; } else { lp.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL; } mWindow.setAttributes(lp); - mWindow.setLayout(WRAP_CONTENT, WRAP_CONTENT); mDialog.setContentView(R.layout.volume_dialog); mDialogView = mDialog.findViewById(R.id.volume_dialog); + FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) mDialogView.getLayoutParams(); + if(!isAudioPanelOnLeftSide()){ + params.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL; + } else { + params.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL; + } + mDialogView.setLayoutParams(params); + mDialogView.setLayoutDirection( + isAudioPanelOnLeftSide() ? View.LAYOUT_DIRECTION_LTR : View.LAYOUT_DIRECTION_RTL); mDialogView.setAlpha(0); mDialog.setCanceledOnTouchOutside(true); mDialog.setOnShowListener(dialog -> { - if (!isLandscape()) mDialogView.setTranslationX((mDialogView.getWidth() / 2.0f)*(!isAudioPanelOnLeftSide() ? 1 : -1)); + ThreadUtils.postOnBackgroundThread(() -> { + if (mLocalMediaManager == null) { + LocalBluetoothManager lbm = Dependency.get(LocalBluetoothManager.class); + InfoMediaManager imm = new InfoMediaManager(mContext, null, null, lbm); + mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, null); + mLocalMediaManager.registerCallback(VolumeDialogImpl.this); + } + mLocalMediaManager.startScan(); + }); + if (!isLandscape()) { + mDialogView.setTranslationX( + (mDialogView.getWidth() / 2.0f) * (!isAudioPanelOnLeftSide() ? 1 : -1)); + } mDialogView.setAlpha(0); mDialogView.animate() .alpha(1) @@ -273,6 +359,7 @@ public class VolumeDialogImpl implements VolumeDialog, if (mRinger != null) { mRingerIcon = mRinger.findViewById(R.id.ringer_icon); mZenIcon = mRinger.findViewById(R.id.dnd_icon); + Util.setVisOrGone(mRinger, !mHasAlertSlider); } mODICaptionsView = mDialog.findViewById(R.id.odi_captions); @@ -284,17 +371,16 @@ public class VolumeDialogImpl implements VolumeDialog, mDialogView.removeView(mODICaptionsTooltipViewStub); mODICaptionsTooltipViewStub = null; } - if (mHasAlertSlider) { - mRinger.setVisibility(View.GONE); - } - if(!isAudioPanelOnLeftSide()) { - mRinger.setForegroundGravity(Gravity.RIGHT); - } else { - mRinger.setForegroundGravity(Gravity.LEFT); - } - mSettingsView = mDialog.findViewById(R.id.settings_container); - mSettingsIcon = mDialog.findViewById(R.id.settings); + mExpandRowsView = mDialog.findViewById(R.id.expandable_indicator_container); + mExpandRows = mExpandRowsView.findViewById(R.id.expandable_indicator); + mExpandRows.setScaleY(isAudioPanelOnLeftSide() ? -1f : 1f); + + mMediaOutputView = mDialog.findViewById(R.id.media_output_container); + mMediaOutputScrollView = mDialog.findViewById(R.id.media_output_scroller); + mMediaButtonView = mDialog.findViewById(R.id.media_button_view); + mMediaButton = mDialog.findViewById(R.id.media_button); + mMediaTitleText = mDialog.findViewById(R.id.media_output_title); if (mRows.isEmpty()) { if (!AudioSystem.isSingleVolume(mContext)) { @@ -312,7 +398,8 @@ public class VolumeDialogImpl implements VolumeDialog, R.drawable.ic_volume_notification_mute, true, false); } addRow(STREAM_ALARM, - R.drawable.ic_alarm, R.drawable.ic_volume_alarm_mute, true, false); + com.android.internal.R.drawable.ic_audio_alarm, + com.android.internal.R.drawable.ic_audio_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); @@ -325,12 +412,29 @@ public class VolumeDialogImpl implements VolumeDialog, addExistingRows(); } + if (Util.isVoiceCapable(mContext) && mState != null) { + updateNotificationRowH(); + } + updateRowsH(getActiveRow()); initRingerH(); initSettingsH(); initODICaptionsH(); } + private final OnComputeInternalInsetsListener mInsetsListener = internalInsetsInfo -> { + internalInsetsInfo.touchableRegion.setEmpty(); + internalInsetsInfo.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION); + int[] mainLocation = new int[2]; + mDialogView.getLocationInWindow(mainLocation); + internalInsetsInfo.touchableRegion.set( + mainLocation[0], + mainLocation[1], + mainLocation[0] + mDialogView.getWidth(), + mainLocation[1] + mDialogView.getHeight() + ); + }; + protected ViewGroup getDialogView() { return mDialogView; } @@ -373,26 +477,84 @@ public class VolumeDialogImpl implements VolumeDialog, 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, 0); - } else { - mDialogRowsView.addView(row.view); - } + mDialogRowsView.addView(row.view, 0); mRows.add(row); } private void addExistingRows() { - int N = mRows.size(); - for (int i = 0; i < N; i++) { - final VolumeRow row = mRows.get(i); + for (VolumeRow row : mRows) { initRow(row, row.stream, row.iconRes, row.iconMuteRes, row.important, row.defaultStream); - if(!isAudioPanelOnLeftSide()){ - mDialogRowsView.addView(row.view, 0); + mDialogRowsView.addView(row.view, 0); + updateVolumeRowH(row); + } + } + + private void cleanExpandedRows() { + VolumeRow ring = findRow(STREAM_RING); + VolumeRow alarm = findRow(STREAM_ALARM); + VolumeRow media = findRow(STREAM_MUSIC); + VolumeRow notification = findRow(STREAM_NOTIFICATION); + VolumeRow active = getActiveRow(); + + float width = mWidth + mSpacer; + float z = mElevation; + + boolean isMediaButtonVisible = mMediaButtonView.getVisibility() == VISIBLE; + + if (isMediaButtonVisible && !mODIServiceComponentEnabled) { + animateViewOut(mMediaButtonView, false, width, z); + } else if (mODIServiceComponentEnabled) { + float widthMedia = width; + if (isMediaButtonVisible) { + animateViewOut(mMediaButtonView, false, widthMedia, z/2); + widthMedia += widthMedia; + } + animateViewOut(mODICaptionsView, false, widthMedia, z); + hideCaptionsTooltip(); + } + + boolean isNotificationEnabled = notification != null && !mState.linkedNotification; + if (isNotificationEnabled) { + final boolean isNotifVisible = active == notification; + animateViewOut(notification.view, isNotifVisible, 0, z); + z /= 2; + } + if (alarm != null) { + final boolean isAlarmVisible = active == alarm; + animateViewOut(alarm.view, isAlarmVisible, isNotificationEnabled ? width : 0, z); + z /= 2; + width = isAlarmVisible ? 0 : width; + } + if (ring != null) { + final boolean isRingVisible = active == ring; + animateViewOut(ring.view, isRingVisible, width, z); + z /= 2; + width += isRingVisible ? 0 : (mWidth + mSpacer); + } + if (media != null) { + Util.setVisOrGone(media.view, true); + animateViewOut(media.view, true, width, z); + } + if (mShowingMediaDevices) { + mDialogRowsView.setAlpha(1f); + final ColorStateList tint = Utils.getColorAttr(mContext, + android.R.attr.colorControlNormal); + mMediaButton.setImageTintList(tint); + mMediaTitleText.setSelected(false); + mShowingMediaDevices = false; + if (mExpanded) { + if (mCurrAnimator != null && mCurrAnimator.isRunning()) { + mCurrAnimator.cancel(); + } + int x = (int) (isAudioPanelOnLeftSide() ? 0 : (3 * mWidth + 2 * mSpacer)); + int endRadius = (int) Math.hypot(3 * mWidth + 2 * mSpacer, mHeight); + mCurrAnimator = circularExit(mMediaOutputScrollView, x, endRadius); + mCurrAnimator.start(); } else { - mDialogRowsView.addView(row.view); + Util.setVisOrGone(mMediaOutputScrollView, false); + Util.setVisOrGone(mDialogRowsView, true); } - updateVolumeRowH(row); } } @@ -442,7 +604,8 @@ public class VolumeDialogImpl implements VolumeDialog, row.iconMuteRes = iconMuteRes; row.important = important; row.defaultStream = defaultStream; - row.view = mDialog.getLayoutInflater().inflate(R.layout.volume_dialog_row, null); + row.view = mDialog.getLayoutInflater().inflate(R.layout.volume_dialog_row, + mDialogRowsView, false); row.view.setId(row.stream); row.view.setTag(row); row.header = row.view.findViewById(R.id.volume_row_header); @@ -458,57 +621,356 @@ public class VolumeDialogImpl implements VolumeDialog, row.icon = row.view.findViewById(R.id.volume_row_icon); row.icon.setImageResource(iconRes); - if (row.stream != AudioSystem.STREAM_ACCESSIBILITY) { - row.icon.setOnClickListener(v -> { - Events.writeEvent(Events.EVENT_ICON_CLICK, row.stream, row.iconState); - mController.setActiveStream(row.stream); - if (row.stream == AudioManager.STREAM_RING) { - final boolean hasVibrator = mController.hasVibrator(); - if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) { - if (hasVibrator) { - mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, false); - } else { - final boolean wasZero = row.ss.level == 0; - mController.setStreamVolume(stream, - wasZero ? row.lastAudibleLevel : 0); - } - } else { - mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false); - if (row.ss.level == 0) { - mController.setStreamVolume(stream, 1); - } - } - } else { - 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); - } + row.icon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); } public void initSettingsH() { - if (mSettingsView != null) { - mSettingsView.setVisibility( + if (mExpandRowsView != null) { + mExpandRowsView.setVisibility( mDeviceProvisionedController.isCurrentUserSetup() && mActivityManager.getLockTaskModeState() == LOCK_TASK_MODE_NONE ? VISIBLE : GONE); } - if (mSettingsIcon != null) { - mSettingsIcon.setOnClickListener(v -> { + 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); Dependency.get(MediaOutputDialogFactory.class).dismiss(); Dependency.get(ActivityStarter.class).startActivity(intent, true /* dismissShade */); + return true; + }); + mMediaButton.setOnClickListener(v -> { + int x = (int) (isLandscape() ? (isAudioPanelOnLeftSide() ? ( + (mWidth + mSpacer) * (mHasAlertSlider ? 1 : 2) + mWidth / 2) + : (mHasAlertSlider ? mWidth * 1.5 + mSpacer : mWidth / 2)) + : (1.5 * mWidth + mSpacer)); + int endRadius = (int) Math.hypot((isLandscape() ? 2.2 : 1.1) * (1.5 * mWidth + + mSpacer), mHeight); + if (mShowingMediaDevices) { + mShowingMediaDevices = false; + if (mCurrAnimator != null && mCurrAnimator.isRunning()) { + mCurrAnimator.cancel(); + } + VolumeRow media = findRow(STREAM_MUSIC); + VolumeRow notification = findRow(STREAM_NOTIFICATION); + if (media != null && notification != null && !mState.linkedNotification) { + animateViewIn(media.view, false, mWidth + mSpacer, mElevation); + } + mCurrAnimator = circularExit(mMediaOutputScrollView, x, endRadius); + } else { + mShowingMediaDevices = true; + if (mCurrAnimator != null && mCurrAnimator.isRunning()) { + mCurrAnimator.cancel(); + } + VolumeRow media = findRow(STREAM_MUSIC); + VolumeRow notification = findRow(STREAM_NOTIFICATION); + if (media != null && notification != null && !mState.linkedNotification) { + animateViewOut(media.view, true, mWidth + mSpacer, mElevation); + } + mCurrAnimator = circularReveal(mMediaOutputScrollView, x, endRadius); + } + mCurrAnimator.start(); + final ColorStateList tint = mShowingMediaDevices + ? Utils.getColorAccent(mContext) + : Utils.getColorAttr(mContext, android.R.attr.colorControlNormal); + mMediaButton.setImageTintList(tint); + + provideTouchHapticH(VibrationEffect.get(VibrationEffect.EFFECT_TICK)); + }); + mExpandRows.setOnClickListener(v -> { + if (!mExpanded) { + VolumeRow ring = findRow(STREAM_RING); + VolumeRow alarm = findRow(STREAM_ALARM); + VolumeRow media = findRow(STREAM_MUSIC); + VolumeRow notification = findRow(STREAM_NOTIFICATION); + VolumeRow active = getActiveRow(); + + if (mHeight == 0 || mWidth == 0) { + mHeight = (float) active.view.getHeight(); + mWidth = (float) active.view.getWidth(); + } + + float width = mWidth + mSpacer; + float z = mElevation; + + boolean showMediaOutput = !Utils.isAudioModeOngoingCall(mContext) && + mMediaOutputView.getChildCount() > 0; + + if (showMediaOutput && !mODIServiceComponentEnabled) { + animateViewIn(mMediaButtonView, false, width, z); + } else if (mODIServiceComponentEnabled) { + float widthMedia = width; + if (showMediaOutput) { + animateViewIn(mMediaButtonView, false, widthMedia, z / 2); + widthMedia += widthMedia; + } + animateViewIn(mODICaptionsView, false, widthMedia, z); + if (mPendingOdiCaptionsTooltip && mODICaptionsView != null) { + showCaptionsTooltip(); + mPendingOdiCaptionsTooltip = false; + } + } + + boolean isNotificationEnabled = notification != null && !mState.linkedNotification; + if (isNotificationEnabled) { + final boolean isNotifVisible = active == notification; + animateViewIn(notification.view, isNotifVisible, 0, z); + z /= 2; + } + if (alarm != null) { + final boolean isAlarmVisible = active == alarm; + animateViewIn(alarm.view, isAlarmVisible, isNotificationEnabled ? width : 0, z); + z /= 2; + width = isAlarmVisible ? 0 : width; + } + if (ring != null) { + final boolean isRingVisible = active == ring; + animateViewIn(ring.view, isRingVisible, width, z); + z /= 2; + width += isRingVisible ? 0 : (mWidth + mSpacer); + } + if (media != null) { + animateViewIn(media.view, true, width, z); + } + + provideTouchHapticH(VibrationEffect.get(VibrationEffect.EFFECT_TICK)); + mExpanded = true; + } else { + cleanExpandedRows(); + provideTouchHapticH(VibrationEffect.get(VibrationEffect.EFFECT_TICK)); + mExpanded = false; + } + mExpandRows.setExpanded(mExpanded); }); } } + private Animator circularReveal(View view, int x, int endRadius) { + if (view == null) return null; + + Animator anim = ViewAnimationUtils.createCircularReveal(view, x, + isLandscape() ? 0 : (int) mHeight, 0, endRadius); + + anim.setDuration(DIALOG_SHOW_ANIMATION_DURATION); + anim.setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator()); + anim.addListener(new Animator.AnimatorListener() { + private boolean mIsCancelled; + private ViewPropertyAnimator mRowsAnimator; + + @Override + public void onAnimationStart(Animator animation) { + mIsCancelled = false; + Util.setVisOrGone(view, true); + mRowsAnimator = mDialogRowsView.animate() + .alpha(0f) + .setDuration(DIALOG_SHOW_ANIMATION_DURATION) + .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator()); + mRowsAnimator.start(); + } + + @Override + public void onAnimationEnd (Animator animation) { + Util.setVisOrGone(mDialogRowsView, mIsCancelled); + mHandler.postDelayed(() -> mMediaTitleText.setSelected(true), 100); + } + + @Override + public void onAnimationRepeat (Animator animation) { } + + @Override + public void onAnimationCancel (Animator animation) { + mIsCancelled = true; + mRowsAnimator.cancel(); + } + }); + return anim; + } + + private Animator circularExit(View view, int x, int endRadius) { + if (view == null) return null; + + Animator anim = ViewAnimationUtils.createCircularReveal(view, x, + isLandscape() ? 0 : (int) mHeight, endRadius, 0); + + anim.setDuration(DIALOG_SHOW_ANIMATION_DURATION); + anim.setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator()); + anim.addListener(new Animator.AnimatorListener() { + private boolean mIsCancelled; + + @Override + public void onAnimationStart(Animator animation) { + mIsCancelled = false; + Util.setVisOrGone(mDialogRowsView, true); + mDialogRowsView.setAlpha(1f); + } + + @Override + public void onAnimationEnd (Animator animation) { + Util.setVisOrGone(view, mIsCancelled); + mMediaTitleText.setSelected(false); + } + + @Override + public void onAnimationRepeat (Animator animation) { } + + @Override + public void onAnimationCancel (Animator animation) { + mIsCancelled = true; + } + }); + return anim; + } + + private void animateViewIn(View view, boolean wasVisible, float startX, float startZ) { + if (view == null) return; + + float startAlpha = 0f; + if (wasVisible) { + startZ = 0; + startAlpha = 1f; + } else { + startZ = -startZ; + } + + view.setTranslationX(isAudioPanelOnLeftSide() ? -startX : startX); + view.setTranslationZ(startZ); + view.setAlpha(startAlpha); + Util.setVisOrGone(view, true); + view.animate() + .alpha(1f) + .translationX(0f) + .translationZ(0f) + .withLayer() + .setDuration(DIALOG_SHOW_ANIMATION_DURATION) + .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator()) + .withEndAction(() -> { + view.setTranslationX(0f); + view.setTranslationZ(0f); + Util.setVisOrGone(view, true); + }) + .start(); + } + + private void animateViewOut(View view, boolean stayVisible, float endX, float endZ) { + if (view == null) return; + + float endAlpha = 0f; + if (stayVisible) { + endZ = 0; + endAlpha = 1f; + } else { + endZ = -endZ; + } + + view.animate() + .alpha(endAlpha) + .translationX(isAudioPanelOnLeftSide() ? -endX : endX) + .translationZ(endZ) + .withLayer() + .setDuration(DIALOG_SHOW_ANIMATION_DURATION) + .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator()) + .withEndAction(() -> { + view.setTranslationX(0); + view.setTranslationZ(0); + Util.setVisOrGone(view, stayVisible); + view.setAlpha(1); + }) + .start(); + } + + @Override + public void onDeviceListUpdate(List<MediaDevice> devices) { + if (!mHandler.hasMessages(H.UPDATE_MEDIA_OUTPUT_VIEW)) { + mHandler.sendMessageDelayed(mHandler.obtainMessage(H.UPDATE_MEDIA_OUTPUT_VIEW, devices), 20); + } + } + + @Override + public void onSelectedDeviceStateChanged(MediaDevice device, int state) { + // Do nothing + } + + private void updateMediaOutputViewH(List<MediaDevice> devices) { + // update/add/remove existing views + for (MediaOutputRow row : mMediaOutputRows) { + if (devices.contains(row.device)) { + if (row.device.isConnected()) { + boolean active = row.device.equals(mLocalMediaManager.getCurrentConnectedDevice()); + row.name.setText(row.device.getName()); + Util.setVisOrGone(row.summary, !row.device.getSummary().equals("")); + row.summary.setText(row.device.getSummary()); + Util.setVisOrGone(row.selected, active); + if (!row.addedToGroup) { + mMediaOutputView.addView(row.view); + row.addedToGroup = true; + } + } else { + mMediaOutputView.removeView(row.view); + row.addedToGroup = false; + } + // remove the device that has been handled + devices.remove(row.device); + } else { + mMediaOutputView.removeView(row.view); + row.addedToGroup = false; + } + } + + try { + // handle the remaining devices + for (MediaDevice device : devices) { + if (device.isConnected()) { + // This device does not have a corresponding row yet, make one. + MediaOutputRow row = new MediaOutputRow(); + boolean active = device.equals(mLocalMediaManager.getCurrentConnectedDevice()); + row.device = device; + row.view = mDialog.getLayoutInflater().inflate(R.layout.volume_dialog_media_output, + mMediaOutputView, false); + row.view.setOnClickListener(v -> { + provideTouchHapticH(VibrationEffect.get(VibrationEffect.EFFECT_CLICK)); + ThreadUtils.postOnBackgroundThread(() -> { + mLocalMediaManager.connectDevice(device); + }); + }); + row.name = row.view.findViewById(R.id.media_output_text); + row.summary = row.view.findViewById(R.id.media_output_summary); + row.selected = row.view.findViewById(R.id.media_output_selected); + row.icon = row.view.findViewById(R.id.media_output_icon); + Drawable drawable = device.getIcon(); + if (drawable == null) { + drawable = mContext.getDrawable( + com.android.internal.R.drawable.ic_bt_headphones_a2dp); + } + row.icon.setImageDrawable(drawable); + + row.name.setText(device.getName()); + Util.setVisOrGone(row.summary, !device.getSummary().equals("")); + row.summary.setText(device.getSummary()); + Util.setVisOrGone(row.selected, active); + row.name.setSelected(true); + row.summary.setSelected(true); + + row.addedToGroup = true; + mMediaOutputView.addView(row.view); + mMediaOutputRows.add(row); + } + } + } catch (Exception e) { + // nothing to do + } + if (mMediaOutputView.getChildCount() == 1) { + // This means there are no external devices connected + removeAllMediaOutputRows(); + } + } + + private void removeAllMediaOutputRows() { + mMediaOutputView.removeAllViews(); + mMediaOutputRows.clear(); + } + public void initRingerH() { if (mRingerIcon != null) { mRingerIcon.setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_POLITE); @@ -607,28 +1069,25 @@ public class VolumeDialogImpl implements VolumeDialog, .alpha(0.f) .setStartDelay(0) .setDuration(DIALOG_HIDE_ANIMATION_DURATION) - .withEndAction(() -> mODICaptionsTooltipView.setVisibility(INVISIBLE)) + .withEndAction(() -> mODICaptionsTooltipView.setVisibility(GONE)) .start(); } } protected void tryToRemoveCaptionsTooltip() { if (mHasSeenODICaptionsTooltip && mODICaptionsTooltipView != null) { - ViewGroup container = mDialog.findViewById(R.id.volume_dialog_container); - container.removeView(mODICaptionsTooltipView); + mDialogView.removeView(mODICaptionsTooltipView); mODICaptionsTooltipView = null; } } private void updateODICaptionsH(boolean isServiceComponentEnabled, boolean fromTooltip) { - if (mODICaptionsView != null) { - mODICaptionsView.setVisibility(isServiceComponentEnabled ? VISIBLE : GONE); - } + mODIServiceComponentEnabled = isServiceComponentEnabled; - if (!isServiceComponentEnabled) return; + if (!mODIServiceComponentEnabled) return; updateCaptionsIcon(); - if (fromTooltip) showCaptionsTooltip(); + if (fromTooltip) mPendingOdiCaptionsTooltip = true; } private void updateCaptionsIcon() { @@ -665,6 +1124,8 @@ public class VolumeDialogImpl implements VolumeDialog, effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); break; case RINGER_MODE_VIBRATE: + effect = VibrationEffect.get(VibrationEffect.EFFECT_THUD); + break; default: effect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK); } @@ -673,6 +1134,15 @@ public class VolumeDialogImpl implements VolumeDialog, } } + private void provideTouchHapticH(VibrationEffect effect) { + mController.vibrate(effect); + } + + private void provideSliderHapticFeedbackH() { + VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_TEXTURE_TICK); + mController.vibrate(effect); + } + private void maybeShowToastH(int newRingerMode) { int seenToastCount = Prefs.getInt(mContext, Prefs.Key.SEEN_RINGER_GUIDANCE_COUNT, 0); @@ -719,12 +1189,15 @@ public class VolumeDialogImpl implements VolumeDialog, rescheduleTimeoutH(); if (mConfigChanged) { + removeAllMediaOutputRows(); initDialog(); // resets mShowing to false mConfigurableTexts.update(); + mShowingMediaDevices = false; mConfigChanged = false; } - initSettingsH(); + mDialog.getWindow().getDecorView().getViewTreeObserver() + .addOnComputeInternalInsetsListener(mInsetsListener); mShowing = true; mIsAnimatingDismiss = false; mDialog.show(); @@ -769,6 +1242,15 @@ public class VolumeDialogImpl implements VolumeDialog, Log.d(TAG, "mDialog.dismiss() reason: " + Events.DISMISS_REASONS[reason] + " from: " + Debug.getCaller()); } + if (mLocalMediaManager != null) { + ThreadUtils.postOnBackgroundThread(() -> { + mLocalMediaManager.stopScan(); + }); + } + if (!mShowing) { + // This may happen when dismissing an expanded panel, don't animate again + return; + } mHandler.removeMessages(H.DISMISS); mHandler.removeMessages(H.SHOW); if (mIsAnimatingDismiss) { @@ -791,9 +1273,17 @@ public class VolumeDialogImpl implements VolumeDialog, mDialog.dismiss(); tryToRemoveCaptionsTooltip(); mIsAnimatingDismiss = false; + mExpanded = false; + cleanExpandedRows(); + mExpandRows.setExpanded(mExpanded); }, 50)); - if (!isLandscape()) animator.translationX((mDialogView.getWidth() / 2.0f)*(!isAudioPanelOnLeftSide() ? 1 : -1)); + if (!isLandscape()) { + animator.translationX( + (mDialogView.getWidth() / 2.0f) * (!isAudioPanelOnLeftSide() ? 1 : -1)); + } animator.start(); + mDialog.getWindow().getDecorView().getViewTreeObserver() + .removeOnComputeInternalInsetsListener(mInsetsListener); checkODICaptionsTooltip(true); mController.notifyVisible(false); synchronized (mSafetyWarningLock) { @@ -810,21 +1300,20 @@ public class VolumeDialogImpl implements VolumeDialog, } private boolean shouldBeVisibleH(VolumeRow row, VolumeRow activeRow) { - boolean isActive = row.stream == activeRow.stream; - - if (isActive) { + if (row.stream == activeRow.stream) { return true; } if (!mShowActiveStreamOnly) { - if (row.stream == AudioSystem.STREAM_ACCESSIBILITY) { + if (row.stream == 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) { + if (row.stream == mPrevActiveStream) { + return true; + } + + if (row.stream == STREAM_MUSIC) { return true; } @@ -833,6 +1322,7 @@ public class VolumeDialogImpl implements VolumeDialog, || activeRow.stream == STREAM_ALARM || activeRow.stream == STREAM_VOICE_CALL || activeRow.stream == STREAM_ACCESSIBILITY + || activeRow.stream == STREAM_NOTIFICATION || mDynamic.get(activeRow.stream); } } @@ -845,18 +1335,21 @@ public class VolumeDialogImpl implements VolumeDialog, if (!mShowing) { trimObsoleteH(); } + // apply changes to all rows for (final VolumeRow row : mRows) { final boolean isActive = row == activeRow; final boolean shouldBeVisible = shouldBeVisibleH(row, activeRow); - Util.setVisOrGone(row.view, shouldBeVisible); + if(!mExpanded) { + Util.setVisOrGone(row.view, shouldBeVisible); + } if (row.view.isShown()) { updateVolumeRowTintH(row, isActive); } } } - protected void updateRingerH() { + private void updateRingerH() { if (mRinger != null && mState != null) { final StreamState ss = mState.states.get(AudioManager.STREAM_RING); if (ss == null) { @@ -979,6 +1472,12 @@ public class VolumeDialogImpl implements VolumeDialog, mController.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK)); } + boolean ringerChanged = false; + if (mState != null && state != null + && mState.ringerModeInternal != state.ringerModeInternal) { + ringerChanged = true; + } + mState = state; mDynamic.clear(); // add any new dynamic rows @@ -1016,12 +1515,28 @@ public class VolumeDialogImpl implements VolumeDialog, } private void updateNotificationRowH() { - VolumeRow notificationRow = findRow(AudioManager.STREAM_NOTIFICATION); - if (notificationRow != null && mState.linkedNotification) { - removeRow(notificationRow); - } else if (notificationRow == null && !mState.linkedNotification) { - addRow(AudioManager.STREAM_NOTIFICATION, R.drawable.ic_volume_notification, + VolumeRow notificationRow = findRow(STREAM_NOTIFICATION); + VolumeRow alarm = findRow(STREAM_ALARM); + if (notificationRow != null) { + if (mState.linkedNotification) { + removeRow(notificationRow); + } else { + final int alarmIndex = mDialogRowsView.indexOfChild(alarm.view); + final int notifIndex = mDialogRowsView.indexOfChild(notificationRow.view); + if (notifIndex == -1) { + mDialogRowsView.addView(notificationRow.view, alarmIndex); + } else if ((alarmIndex - 1) != notifIndex) { + mDialogRowsView.removeView(notificationRow.view); + mDialogRowsView.addView(notificationRow.view, alarmIndex - 1); + } + } + } else if (notificationRow == null && !mState.linkedNotification + && !AudioSystem.isSingleVolume(mContext)) { + notificationRow = new VolumeRow(); + initRow(notificationRow, STREAM_NOTIFICATION, R.drawable.ic_volume_notification, R.drawable.ic_volume_notification_mute, true, false); + mDialogRowsView.addView(notificationRow.view, mDialogRowsView.indexOfChild(alarm.view)); + mRows.add(notificationRow); } } @@ -1031,9 +1546,6 @@ public class VolumeDialogImpl implements VolumeDialog, final StreamState ss = mState.states.get(row.stream); if (ss == null) return; row.ss = ss; - if (ss.level > 0) { - row.lastAudibleLevel = ss.level; - } if (ss.level == row.requestedLevel) { row.requestedLevel = -1; } @@ -1042,7 +1554,7 @@ public class VolumeDialogImpl implements VolumeDialog, 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 isNotificationStream = row.stream == AudioManager.STREAM_NOTIFICATION; + final boolean isNotificationStream = row.stream == STREAM_NOTIFICATION; final boolean isVibrate = mState.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE; final boolean isRingVibrate = isRingStream && isVibrate; final boolean isRingSilent = isRingStream @@ -1065,21 +1577,12 @@ public class VolumeDialogImpl implements VolumeDialog, 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 - Util.setText(row.header, getStreamLabelH(ss)); - row.slider.setContentDescription(row.header.getText()); - mConfigurableTexts.add(row.header, ss.name); + row.slider.setContentDescription(getStreamLabelH(ss)); // update icon final boolean iconEnabled = (mAutomute || ss.muteSupported) && !zenMuted; row.icon.setEnabled(iconEnabled); - row.icon.setAlpha(iconEnabled ? 1 : 0.5f); final int iconRes = isRingVibrate ? R.drawable.ic_volume_ringer_vibrate : isRingSilent || zenMuted ? row.iconMuteRes @@ -1088,13 +1591,6 @@ public class VolumeDialogImpl implements VolumeDialog, : R.drawable.ic_volume_media_bt : isStreamMuted(ss) ? row.iconMuteRes : row.iconRes; row.icon.setImageResource(iconRes); - row.iconState = - iconRes == R.drawable.ic_volume_ringer_vibrate ? Events.ICON_STATE_VIBRATE - : (iconRes == R.drawable.ic_volume_media_bt_mute || iconRes == row.iconMuteRes) - ? Events.ICON_STATE_MUTE - : (iconRes == R.drawable.ic_volume_media_bt || iconRes == row.iconRes) - ? Events.ICON_STATE_UNMUTE - : Events.ICON_STATE_UNKNOWN; if (iconEnabled) { if (isRingStream) { if (isRingVibrate) { @@ -1158,18 +1654,18 @@ public class VolumeDialogImpl implements VolumeDialog, } boolean useActiveColoring = isActive && row.slider.isEnabled(); final ColorStateList tint = useActiveColoring - ? Utils.getColorAccent(mContext) - : Utils.getColorAttr(mContext, android.R.attr.colorForeground); - final int alpha = useActiveColoring + ? Utils.getColorAccent(mContext).withAlpha(mDarkMode ? + SLIDER_PROGRESS_ALPHA_ACTIVE_DARK : SLIDER_PROGRESS_ALPHA_ACTIVE) + : Utils.getColorAccent(mContext).withAlpha(mDarkMode ? + SLIDER_PROGRESS_ALPHA_DARK : SLIDER_PROGRESS_ALPHA); + final int alpha = useActiveColoring ? Color.alpha(tint.getDefaultColor()) : getAlphaAttr(android.R.attr.secondaryContentAlpha); + final ColorStateList progressTint = useActiveColoring ? null : tint; if (tint == row.cachedTint) return; - row.slider.setProgressTintList(tint); + row.slider.setProgressTintList(progressTint); row.slider.setThumbTintList(tint); - row.slider.setProgressBackgroundTintList(tint); row.slider.setAlpha(((float) alpha) / 255); - row.icon.setImageTintList(tint); - row.icon.setImageAlpha(alpha); row.cachedTint = tint; } @@ -1192,11 +1688,11 @@ public class VolumeDialogImpl implements VolumeDialog, return; // don't update if visible and in grace period } if (vlevel == level) { - if (mShowing && rowVisible) { + if (mShowing && rowVisible && !row.ss.muted) { return; // don't clamp if visible } } - final int newProgress = vlevel * 100; + final int newProgress = row.ss.muted ? 0 : vlevel * 100; if (progress != newProgress) { if (mShowing && rowVisible) { // animate! @@ -1223,6 +1719,10 @@ public class VolumeDialogImpl implements VolumeDialog, row.slider.setProgress(newProgress, true); } } + + // update header text + Util.setText(row.header, Utils.formatPercentage((enable && !row.ss.muted) + ? vlevel : 0, row.ss.levelMax)); } private void recheckH(VolumeRow row) { @@ -1381,6 +1881,12 @@ public class VolumeDialogImpl implements VolumeDialog, private static final int SET_STREAM_IMPORTANT = 5; private static final int RESCHEDULE_TIMEOUT = 6; private static final int STATE_CHANGED = 7; + private static final int PERFORM_HAPTIC_FEEDBACK = 8; + private static final int UPDATE_MEDIA_OUTPUT_VIEW = 9; + + public H(Looper l) { + super(l); + } public H() { super(Looper.getMainLooper()); @@ -1396,6 +1902,8 @@ public class VolumeDialogImpl implements VolumeDialog, case SET_STREAM_IMPORTANT: setStreamImportantH(msg.arg1, msg.arg2 != 0); break; case RESCHEDULE_TIMEOUT: rescheduleTimeoutH(); break; case STATE_CHANGED: onStateChangedH(mState); break; + case PERFORM_HAPTIC_FEEDBACK: provideSliderHapticFeedbackH(); break; + case UPDATE_MEDIA_OUTPUT_VIEW: updateMediaOutputViewH((List<MediaDevice>) msg.obj); break; } } } @@ -1426,10 +1934,8 @@ public class VolumeDialogImpl implements VolumeDialog, @Override public boolean onTouchEvent(MotionEvent event) { if (mShowing) { - if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { - dismissH(Events.DISMISS_REASON_TOUCH_OUTSIDE); - return true; - } + dismissH(Events.DISMISS_REASON_TOUCH_OUTSIDE); + return true; } return false; } @@ -1447,6 +1953,12 @@ public class VolumeDialogImpl implements VolumeDialog, if (mRow.ss == null) return; if (D.BUG) Log.d(TAG, AudioSystem.streamToString(mRow.stream) + " onProgressChanged " + progress + " fromUser=" + fromUser); + if ((mRow.stream == STREAM_RING || mRow.stream == STREAM_NOTIFICATION) && mHasAlertSlider) { + if (mRow.ss.muted) { + seekBar.setProgress(0); + return; + } + } if (!fromUser) return; if (mRow.ss.levelMin > 0) { final int minProgress = mRow.ss.levelMin * 100; @@ -1456,6 +1968,17 @@ public class VolumeDialogImpl implements VolumeDialog, } } final int userLevel = getImpliedLevel(seekBar, progress); + + if ((mRow.stream == STREAM_RING || mRow.stream == STREAM_NOTIFICATION) && mHasAlertSlider) { + if (mRow.ss.level > mRow.ss.levelMin && userLevel == 0) { + seekBar.setProgress((mRow.ss.levelMin + 1) * 100); + Util.setText(mRow.header, + Utils.formatPercentage(mRow.ss.levelMin + 1, mRow.ss.levelMax)); + return; + } + } + + Util.setText(mRow.header, Utils.formatPercentage(userLevel, mRow.ss.levelMax)); if (mRow.ss.level != userLevel || mRow.ss.muted && userLevel > 0) { mRow.userAttempt = SystemClock.uptimeMillis(); if (mRow.requestedLevel != userLevel) { @@ -1464,6 +1987,10 @@ public class VolumeDialogImpl implements VolumeDialog, mRow.requestedLevel = userLevel; Events.writeEvent(Events.EVENT_TOUCH_LEVEL_CHANGED, mRow.stream, userLevel); + + if (mVibrateOnSlider && !mHandler.hasMessages(H.PERFORM_HAPTIC_FEEDBACK)) { + mHandler.sendEmptyMessageDelayed(H.PERFORM_HAPTIC_FEEDBACK, 20); + } } } } @@ -1516,7 +2043,7 @@ public class VolumeDialogImpl implements VolumeDialog, private static class VolumeRow { private View view; private TextView header; - private ImageButton icon; + private ImageView icon; private SeekBar slider; private int stream; private StreamState ss; @@ -1528,10 +2055,18 @@ public class VolumeDialogImpl implements VolumeDialog, 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 = 1; private FrameLayout dndIcon; } + + private static class MediaOutputRow { + private View view; + private TextView name; + private TextView summary; + private ImageView icon; + private ImageView selected; + private MediaDevice device; + private boolean addedToGroup; + } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeToolTipView.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeToolTipView.java index 1de55856f942..44a76f536a7e 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeToolTipView.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeToolTipView.java @@ -17,6 +17,8 @@ package com.android.systemui.volume; import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.CornerPathEffect; import android.graphics.Paint; import android.graphics.drawable.ShapeDrawable; @@ -60,9 +62,20 @@ public class VolumeToolTipView extends LinearLayout { private void drawArrow() { View arrowView = findViewById(R.id.arrow); + + boolean isLandscape = getContext().getResources().getConfiguration().orientation + == Configuration.ORIENTATION_LANDSCAPE; ViewGroup.LayoutParams arrowLp = arrowView.getLayoutParams(); - ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.createHorizontal( - arrowLp.width, arrowLp.height, false)); + int arrowHeight = arrowLp.height; + int arrowWidth = arrowLp.width; + + ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.create(arrowWidth, arrowHeight, true)); + if (isLandscape) { + boolean isPointingLeft = getContext().getResources().getBoolean( + R.bool.config_audioPanelOnLeftSide); + arrowView.setRotation(isPointingLeft ? 270 : 90); + } + Paint arrowPaint = arrowDrawable.getPaint(); TypedValue typedValue = new TypedValue(); getContext().getTheme().resolveAttribute(android.R.attr.colorAccent, typedValue, true); @@ -71,6 +84,5 @@ public class VolumeToolTipView extends LinearLayout { arrowPaint.setPathEffect(new CornerPathEffect( getResources().getDimension(R.dimen.volume_tool_tip_arrow_corner_radius))); arrowView.setBackground(arrowDrawable); - } } |