Merge "Add Play/Pause Icon & Background Animations" into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
4c07041a1b
@@ -1,26 +1,91 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2022 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="14dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="14"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M9.1818,15.6363H13.5455V0.3635H9.1818V15.6363ZM0.4546,15.6363H4.8182V0.3635H0.4546V15.6363Z"
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2022 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License
|
||||
-->
|
||||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24">
|
||||
<group android:name="_R_G">
|
||||
<group android:name="_R_G_L_1_G"
|
||||
android:translateX="12"
|
||||
android:translateY="12.125">
|
||||
<path android:name="_R_G_L_1_G_D_0_P_0"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData=" M-6 7 C-6,7 -2,7 -2,7 C-2,7 -2,-7 -2,-7 C-2,-7 -6,-7 -6,-7 C-6,-7 -6,7 -6,7c "/>
|
||||
</group>
|
||||
<group android:name="_R_G_L_0_G"
|
||||
android:translateX="12"
|
||||
android:translateY="12.125">
|
||||
<path android:name="_R_G_L_0_G_D_0_P_0"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData=" M2 7 C2,7 6,7 6,7 C6,7 6,-0.12 6,-0.12 C6,-0.12 6,-7 6,-7 C6,-7 2,-7 2,-7 C2,-7 2,7 2,7c "/>
|
||||
</group>
|
||||
</group>
|
||||
<group android:name="time_group"/>
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
<target android:name="_R_G_L_1_G_D_0_P_0">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator android:propertyName="pathData"
|
||||
android:duration="333"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="M-6 7 C-6,7 -2,7 -2,7 C-2,7 -2,-7 -2,-7 C-2,-7 -6,-7 -6,-7 C-6,-7 -6,7 -6,7c "
|
||||
android:valueTo="M-6 7 C-6,7 -2,3.94 -2,3.94 C-2,3.94 -2,-4.37 -2,-4.37 C-2,-4.37 -6,-7 -6,-7 C-6,-7 -6,7 -6,7c "
|
||||
android:valueType="pathType">
|
||||
<aapt:attr name="android:interpolator">
|
||||
<pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
|
||||
</aapt:attr>
|
||||
</objectAnimator>
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="_R_G_L_0_G_D_0_P_0">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator android:propertyName="pathData"
|
||||
android:duration="333"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="M2 7 C2,7 6,7 6,7 C6,7 6,-0.12 6,-0.12 C6,-0.12 6,-7 6,-7 C6,-7 2,-7 2,-7 C2,-7 2,7 2,7c "
|
||||
android:valueTo="M-5.62 7 C-5.62,7 -4.75,7 -4.75,7 C-4.75,7 6,-0.12 6,-0.12 C6,-0.12 -4.44,-7 -4.44,-7 C-4.44,-7 -5.62,-7 -5.62,-7 C-5.62,-7 -5.62,7 -5.62,7c "
|
||||
android:valueType="pathType">
|
||||
<aapt:attr name="android:interpolator">
|
||||
<pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
|
||||
</aapt:attr>
|
||||
</objectAnimator>
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="time_group">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator android:propertyName="translateX"
|
||||
android:duration="517"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="1"
|
||||
android:valueType="floatType"/>
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
</animated-vector>
|
||||
73
packages/SystemUI/res/drawable/ic_media_pause_container.xml
Normal file
73
packages/SystemUI/res/drawable/ic_media_pause_container.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2022 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License
|
||||
-->
|
||||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector android:height="48dp"
|
||||
android:width="48dp"
|
||||
android:viewportHeight="48"
|
||||
android:viewportWidth="48">
|
||||
<group android:name="_R_G">
|
||||
<group android:name="_R_G_L_1_G"
|
||||
android:translateX="24"
|
||||
android:translateY="24"
|
||||
android:scaleX="0.5"
|
||||
android:scaleY="0.5"/>
|
||||
<group android:name="_R_G_L_0_G"
|
||||
android:translateX="24"
|
||||
android:translateY="24"
|
||||
android:scaleX="0.5"
|
||||
android:scaleY="0.5">
|
||||
<path android:name="_R_G_L_0_G_D_0_P_0"
|
||||
android:fillColor="#ffddb3"
|
||||
android:fillAlpha="1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData=" M48 -16 C48,-16 48,16 48,16 C48,33.67 33.67,48 16,48 C16,48 -16,48 -16,48 C-33.67,48 -48,33.67 -48,16 C-48,16 -48,-16 -48,-16 C-48,-33.67 -33.67,-48 -16,-48 C-16,-48 16,-48 16,-48 C33.67,-48 48,-33.67 48,-16c "/>
|
||||
</group>
|
||||
</group>
|
||||
<group android:name="time_group"/>
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
<target android:name="_R_G_L_0_G_D_0_P_0">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator android:propertyName="pathData"
|
||||
android:duration="500"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="M48 -16 C48,-16 48,16 48,16 C48,33.67 33.67,48 16,48 C16,48 -16,48 -16,48 C-33.67,48 -48,33.67 -48,16 C-48,16 -48,-16 -48,-16 C-48,-33.67 -33.67,-48 -16,-48 C-16,-48 16,-48 16,-48 C33.67,-48 48,-33.67 48,-16c "
|
||||
android:valueTo="M48 0.25 C48,0.25 48,0 48,0 C47.75,26 31.25,48 0,48 C0,48 0,48 0,48 C-30,48 -48,25.75 -48,-0.25 C-48,-0.25 -48,-0.25 -48,-0.25 C-47.75,-23.5 -32.25,-47.75 0.5,-48 C0.5,-48 0.5,-48 0.5,-48 C28,-47.75 47.75,-29.75 48,0.25c "
|
||||
android:valueType="pathType">
|
||||
<aapt:attr name="android:interpolator">
|
||||
<pathInterpolator android:pathData="M 0.0,0.0 c0.526,0 0,1 1.0,1.0"/>
|
||||
</aapt:attr>
|
||||
</objectAnimator>
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="time_group">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator android:propertyName="translateX"
|
||||
android:duration="517"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="1"
|
||||
android:valueType="floatType"/>
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
</animated-vector>
|
||||
@@ -1,26 +1,91 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2022 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M20,12L6,21V3L20,12ZM15.26,12L8.55,7.68V16.32L15.26,12Z"
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2022 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License
|
||||
-->
|
||||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24">
|
||||
<group android:name="_R_G">
|
||||
<group android:name="_R_G_L_1_G"
|
||||
android:translateX="12"
|
||||
android:translateY="12.125">
|
||||
<path android:name="_R_G_L_1_G_D_0_P_0"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData=" M-6 7 C-6,7 -2,3.94 -2,3.94 C-2,3.94 -2,-4.37 -2,-4.37 C-2,-4.37 -6,-7 -6,-7 C-6,-7 -6,7 -6,7c "/>
|
||||
</group>
|
||||
<group android:name="_R_G_L_0_G"
|
||||
android:translateX="12"
|
||||
android:translateY="12.125">
|
||||
<path android:name="_R_G_L_0_G_D_0_P_0"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData=" M-5.62 7 C-5.62,7 -4.75,7 -4.75,7 C-4.75,7 6,-0.12 6,-0.12 C6,-0.12 -4.44,-7 -4.44,-7 C-4.44,-7 -5.62,-7 -5.62,-7 C-5.62,-7 -5.62,7 -5.62,7c "/>
|
||||
</group>
|
||||
</group>
|
||||
<group android:name="time_group"/>
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
<target android:name="_R_G_L_1_G_D_0_P_0">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator android:propertyName="pathData"
|
||||
android:duration="333"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="M-6 7 C-6,7 -2,3.94 -2,3.94 C-2,3.94 -2,-4.37 -2,-4.37 C-2,-4.37 -6,-7 -6,-7 C-6,-7 -6,7 -6,7c "
|
||||
android:valueTo="M-6 7 C-6,7 -2,7 -2,7 C-2,7 -2,-7 -2,-7 C-2,-7 -6,-7 -6,-7 C-6,-7 -6,7 -6,7c "
|
||||
android:valueType="pathType">
|
||||
<aapt:attr name="android:interpolator">
|
||||
<pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
|
||||
</aapt:attr>
|
||||
</objectAnimator>
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="_R_G_L_0_G_D_0_P_0">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator android:propertyName="pathData"
|
||||
android:duration="333"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="M-5.62 7 C-5.62,7 -4.75,7 -4.75,7 C-4.75,7 6,-0.12 6,-0.12 C6,-0.12 -4.44,-7 -4.44,-7 C-4.44,-7 -5.62,-7 -5.62,-7 C-5.62,-7 -5.62,7 -5.62,7c "
|
||||
android:valueTo="M2 7 C2,7 6,7 6,7 C6,7 6,-0.12 6,-0.12 C6,-0.12 6,-7 6,-7 C6,-7 2,-7 2,-7 C2,-7 2,7 2,7c "
|
||||
android:valueType="pathType">
|
||||
<aapt:attr name="android:interpolator">
|
||||
<pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
|
||||
</aapt:attr>
|
||||
</objectAnimator>
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="time_group">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator android:propertyName="translateX"
|
||||
android:duration="517"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="1"
|
||||
android:valueType="floatType"/>
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
</animated-vector>
|
||||
68
packages/SystemUI/res/drawable/ic_media_play_container.xml
Normal file
68
packages/SystemUI/res/drawable/ic_media_play_container.xml
Normal file
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2022 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License
|
||||
-->
|
||||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector android:height="48dp"
|
||||
android:width="48dp"
|
||||
android:viewportHeight="48"
|
||||
android:viewportWidth="48">
|
||||
<group android:name="_R_G">
|
||||
<group android:name="_R_G_L_0_G"
|
||||
android:translateX="24"
|
||||
android:translateY="24"
|
||||
android:scaleX="0.5"
|
||||
android:scaleY="0.5">
|
||||
<path android:name="_R_G_L_0_G_D_0_P_0"
|
||||
android:fillColor="#ffddb3"
|
||||
android:fillAlpha="1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData=" M48 0.25 C48,0.25 48,0 48,0 C47.75,26 31.25,48 0,48 C0,48 0,48 0,48 C-30,48 -48,25.75 -48,-0.25 C-48,-0.25 -48,-0.25 -48,-0.25 C-47.75,-23.5 -32.25,-47.75 0.5,-48 C0.5,-48 0.5,-48 0.5,-48 C28,-47.75 47.75,-29.75 48,0.25c "/>
|
||||
</group>
|
||||
</group>
|
||||
<group android:name="time_group"/>
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
<target android:name="_R_G_L_0_G_D_0_P_0">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator android:propertyName="pathData"
|
||||
android:duration="500"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="M48 0.25 C48,0.25 48,0 48,0 C47.75,26 31.25,48 0,48 C0,48 0,48 0,48 C-30,48 -48,25.75 -48,-0.25 C-48,-0.25 -48,-0.25 -48,-0.25 C-47.75,-23.5 -32.25,-47.75 0.5,-48 C0.5,-48 0.5,-48 0.5,-48 C28,-47.75 47.75,-29.75 48,0.25c "
|
||||
android:valueTo="M48 -16 C48,-16 48,16 48,16 C48,33.67 33.67,48 16,48 C16,48 -16,48 -16,48 C-33.67,48 -48,33.67 -48,16 C-48,16 -48,-16 -48,-16 C-48,-33.67 -33.67,-48 -16,-48 C-16,-48 16,-48 16,-48 C33.67,-48 48,-33.67 48,-16c "
|
||||
android:valueType="pathType">
|
||||
<aapt:attr name="android:interpolator">
|
||||
<pathInterpolator android:pathData="M 0.0,0.0 c0.518,0 0,1 1.0,1.0"/>
|
||||
</aapt:attr>
|
||||
</objectAnimator>
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="time_group">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator android:propertyName="translateX"
|
||||
android:duration="517"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="1"
|
||||
android:valueType="floatType"/>
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
</animated-vector>
|
||||
@@ -145,8 +145,7 @@
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="@dimen/qs_media_padding"
|
||||
android:layout_marginEnd="@dimen/qs_media_padding"
|
||||
/>
|
||||
android:layout_marginEnd="@dimen/qs_media_padding" />
|
||||
|
||||
<!-- See comment in media_session_collapsed.xml for how these barriers are used -->
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
@@ -184,7 +183,7 @@
|
||||
<!-- Button visibility will be controlled in code -->
|
||||
<ImageButton
|
||||
android:id="@+id/actionPrev"
|
||||
style="@style/MediaPlayer.SessionAction"
|
||||
style="@style/MediaPlayer.SessionAction.Secondary"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="4dp"
|
||||
@@ -211,7 +210,7 @@
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/actionNext"
|
||||
style="@style/MediaPlayer.SessionAction"
|
||||
style="@style/MediaPlayer.SessionAction.Secondary"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="0dp"
|
||||
@@ -221,7 +220,7 @@
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/action0"
|
||||
style="@style/MediaPlayer.SessionAction"
|
||||
style="@style/MediaPlayer.SessionAction.Secondary"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="@dimen/qs_media_action_spacing"
|
||||
@@ -231,7 +230,7 @@
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/action1"
|
||||
style="@style/MediaPlayer.SessionAction"
|
||||
style="@style/MediaPlayer.SessionAction.Secondary"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="@dimen/qs_media_action_spacing"
|
||||
@@ -241,7 +240,7 @@
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/action2"
|
||||
style="@style/MediaPlayer.SessionAction"
|
||||
style="@style/MediaPlayer.SessionAction.Secondary"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="@dimen/qs_media_action_spacing"
|
||||
@@ -251,7 +250,7 @@
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/action3"
|
||||
style="@style/MediaPlayer.SessionAction"
|
||||
style="@style/MediaPlayer.SessionAction.Secondary"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="@dimen/qs_media_action_spacing"
|
||||
@@ -261,7 +260,7 @@
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/action4"
|
||||
style="@style/MediaPlayer.SessionAction"
|
||||
style="@style/MediaPlayer.SessionAction.Secondary"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="@dimen/qs_media_action_spacing"
|
||||
|
||||
@@ -616,7 +616,6 @@
|
||||
parent="@android:style/Widget.Material.Button.Borderless.Small">
|
||||
<item name="android:background">@drawable/qs_media_light_source</item>
|
||||
<item name="android:tint">?android:attr/textColorPrimary</item>
|
||||
<item name="android:stateListAnimator">@anim/media_button_state_list_animator</item>
|
||||
<item name="android:paddingTop">12dp</item>
|
||||
<item name="android:paddingStart">12dp</item>
|
||||
<item name="android:paddingEnd">12dp</item>
|
||||
@@ -629,6 +628,10 @@
|
||||
<item name="android:backgroundTint">@color/media_player_solid_button_bg</item>
|
||||
</style>
|
||||
|
||||
<style name="MediaPlayer.SessionAction.Secondary" parent="MediaPlayer.SessionAction">
|
||||
<item name="android:stateListAnimator">@anim/media_button_state_list_animator</item>
|
||||
</style>
|
||||
|
||||
<style name="MediaPlayer.OutlineButton">
|
||||
<item name="android:background">@drawable/qs_media_outline_button</item>
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
|
||||
@@ -30,13 +30,14 @@ import android.content.res.ColorStateList;
|
||||
import android.graphics.ColorMatrix;
|
||||
import android.graphics.ColorMatrixColorFilter;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Animatable;
|
||||
import android.graphics.drawable.Animatable2;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.media.session.MediaController;
|
||||
import android.media.session.MediaSession;
|
||||
import android.media.session.PlaybackState;
|
||||
import android.os.Process;
|
||||
import android.text.Layout;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
@@ -67,6 +68,7 @@ import com.android.systemui.util.animation.TransitionLayout;
|
||||
import com.android.systemui.util.time.SystemClock;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@@ -637,9 +639,34 @@ public class MediaControlPanel {
|
||||
|
||||
private void setSemanticButton(final ImageButton button, MediaAction mediaAction,
|
||||
ConstraintSet collapsedSet, ConstraintSet expandedSet, boolean showInCompact) {
|
||||
AnimationBindHandler animHandler;
|
||||
if (button.getTag() == null) {
|
||||
animHandler = new AnimationBindHandler();
|
||||
button.setTag(animHandler);
|
||||
} else {
|
||||
animHandler = (AnimationBindHandler) button.getTag();
|
||||
}
|
||||
|
||||
animHandler.tryExecute(() -> {
|
||||
bindSemanticButton(animHandler, button, mediaAction,
|
||||
collapsedSet, expandedSet, showInCompact);
|
||||
});
|
||||
}
|
||||
|
||||
private void bindSemanticButton(final AnimationBindHandler animHandler,
|
||||
final ImageButton button, MediaAction mediaAction, ConstraintSet collapsedSet,
|
||||
ConstraintSet expandedSet, boolean showInCompact) {
|
||||
|
||||
animHandler.unregisterAll();
|
||||
if (mediaAction != null) {
|
||||
button.setImageIcon(mediaAction.getIcon());
|
||||
final Drawable icon = mediaAction.getIcon();
|
||||
button.setImageDrawable(icon);
|
||||
button.setContentDescription(mediaAction.getContentDescription());
|
||||
final Drawable bgDrawable = mediaAction.getBackground();
|
||||
button.setBackground(bgDrawable);
|
||||
|
||||
animHandler.tryRegister(icon);
|
||||
animHandler.tryRegister(bgDrawable);
|
||||
|
||||
Runnable action = mediaAction.getAction();
|
||||
if (action == null) {
|
||||
@@ -651,19 +678,75 @@ public class MediaControlPanel {
|
||||
logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
|
||||
/* isRecommendationCard */ false);
|
||||
action.run();
|
||||
|
||||
if (icon instanceof Animatable) {
|
||||
((Animatable) icon).start();
|
||||
}
|
||||
if (bgDrawable instanceof Animatable) {
|
||||
((Animatable) bgDrawable).start();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
button.setImageIcon(null);
|
||||
button.setImageDrawable(null);
|
||||
button.setContentDescription(null);
|
||||
button.setEnabled(false);
|
||||
button.setBackground(mContext.getDrawable(R.drawable.qs_media_round_button_background));
|
||||
}
|
||||
|
||||
setVisibleAndAlpha(collapsedSet, button.getId(), mediaAction != null && showInCompact);
|
||||
setVisibleAndAlpha(expandedSet, button.getId(), mediaAction != null);
|
||||
}
|
||||
|
||||
private static class AnimationBindHandler extends Animatable2.AnimationCallback {
|
||||
private ArrayList<Runnable> mOnAnimationsComplete = new ArrayList<>();
|
||||
private ArrayList<Animatable2> mRegistrations = new ArrayList<>();
|
||||
|
||||
public void tryRegister(Drawable drawable) {
|
||||
if (drawable instanceof Animatable2) {
|
||||
Animatable2 anim = (Animatable2) drawable;
|
||||
anim.registerAnimationCallback(this);
|
||||
mRegistrations.add(anim);
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterAll() {
|
||||
for (Animatable2 anim : mRegistrations) {
|
||||
anim.unregisterAnimationCallback(this);
|
||||
}
|
||||
mRegistrations.clear();
|
||||
}
|
||||
|
||||
public boolean isAnimationRunning() {
|
||||
for (Animatable2 anim : mRegistrations) {
|
||||
if (anim.isRunning()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void tryExecute(Runnable action) {
|
||||
if (isAnimationRunning()) {
|
||||
mOnAnimationsComplete.add(action);
|
||||
} else {
|
||||
action.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Drawable drawable) {
|
||||
super.onAnimationEnd(drawable);
|
||||
if (!isAnimationRunning()) {
|
||||
for (Runnable action : mOnAnimationsComplete) {
|
||||
action.run();
|
||||
}
|
||||
mOnAnimationsComplete.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ActivityLaunchAnimator.Controller buildLaunchAnimatorController(
|
||||
TransitionLayout player) {
|
||||
|
||||
@@ -170,9 +170,10 @@ data class MediaButton(
|
||||
|
||||
/** State of a media action. */
|
||||
data class MediaAction(
|
||||
val icon: Icon?,
|
||||
val icon: Drawable?,
|
||||
val action: Runnable?,
|
||||
val contentDescription: CharSequence?
|
||||
val contentDescription: CharSequence?,
|
||||
val background: Drawable?
|
||||
)
|
||||
|
||||
/** State of the media device. */
|
||||
|
||||
@@ -695,11 +695,12 @@ class MediaDataManager(
|
||||
Icon.createWithResource(sbn.packageName, action.getIcon()!!.getResId())
|
||||
} else {
|
||||
action.getIcon()
|
||||
}.setTint(themeText)
|
||||
}.setTint(themeText).loadDrawable(context)
|
||||
val mediaAction = MediaAction(
|
||||
mediaActionIcon,
|
||||
runnable,
|
||||
action.title)
|
||||
action.title,
|
||||
context.getDrawable(R.drawable.qs_media_round_button_background))
|
||||
actionIcons.add(mediaAction)
|
||||
}
|
||||
}
|
||||
@@ -789,30 +790,34 @@ class MediaDataManager(
|
||||
return when (action) {
|
||||
PlaybackState.ACTION_PLAY -> {
|
||||
MediaAction(
|
||||
Icon.createWithResource(context, R.drawable.ic_media_play),
|
||||
context.getDrawable(R.drawable.ic_media_play),
|
||||
{ controller.transportControls.play() },
|
||||
context.getString(R.string.controls_media_button_play)
|
||||
context.getString(R.string.controls_media_button_play),
|
||||
context.getDrawable(R.drawable.ic_media_play_container)
|
||||
)
|
||||
}
|
||||
PlaybackState.ACTION_PAUSE -> {
|
||||
MediaAction(
|
||||
Icon.createWithResource(context, R.drawable.ic_media_pause),
|
||||
context.getDrawable(R.drawable.ic_media_pause),
|
||||
{ controller.transportControls.pause() },
|
||||
context.getString(R.string.controls_media_button_pause)
|
||||
context.getString(R.string.controls_media_button_pause),
|
||||
context.getDrawable(R.drawable.ic_media_pause_container)
|
||||
)
|
||||
}
|
||||
PlaybackState.ACTION_SKIP_TO_PREVIOUS -> {
|
||||
MediaAction(
|
||||
Icon.createWithResource(context, R.drawable.ic_media_prev),
|
||||
context.getDrawable(R.drawable.ic_media_prev),
|
||||
{ controller.transportControls.skipToPrevious() },
|
||||
context.getString(R.string.controls_media_button_prev)
|
||||
context.getString(R.string.controls_media_button_prev),
|
||||
context.getDrawable(R.drawable.qs_media_round_button_background)
|
||||
)
|
||||
}
|
||||
PlaybackState.ACTION_SKIP_TO_NEXT -> {
|
||||
MediaAction(
|
||||
Icon.createWithResource(context, R.drawable.ic_media_next),
|
||||
context.getDrawable(R.drawable.ic_media_next),
|
||||
{ controller.transportControls.skipToNext() },
|
||||
context.getString(R.string.controls_media_button_next)
|
||||
context.getString(R.string.controls_media_button_next),
|
||||
context.getDrawable(R.drawable.qs_media_round_button_background)
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
@@ -835,9 +840,10 @@ class MediaDataManager(
|
||||
|
||||
val it = state.customActions[index]
|
||||
return MediaAction(
|
||||
Icon.createWithResource(packageName, it.icon),
|
||||
Icon.createWithResource(packageName, it.icon).loadDrawable(context),
|
||||
{ controller.transportControls.sendCustomAction(it, it.extras) },
|
||||
it.name
|
||||
it.name,
|
||||
context.getDrawable(R.drawable.ic_media_pause_container)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -900,9 +906,11 @@ class MediaDataManager(
|
||||
|
||||
private fun getResumeMediaAction(action: Runnable): MediaAction {
|
||||
return MediaAction(
|
||||
Icon.createWithResource(context, R.drawable.ic_media_play).setTint(themeText),
|
||||
Icon.createWithResource(context, R.drawable.ic_media_play)
|
||||
.setTint(themeText).loadDrawable(context),
|
||||
action,
|
||||
context.getString(R.string.controls_media_resume)
|
||||
context.getString(R.string.controls_media_resume),
|
||||
context.getDrawable(R.drawable.ic_media_play_container)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,9 @@ package com.android.systemui.media
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Animatable2
|
||||
import android.graphics.drawable.AnimatedVectorDrawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.graphics.drawable.Icon
|
||||
import android.graphics.drawable.RippleDrawable
|
||||
import android.media.MediaMetadata
|
||||
import android.media.session.MediaSession
|
||||
@@ -60,6 +61,7 @@ import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.ArgumentMatchers.anyLong
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.any
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.times
|
||||
@@ -290,15 +292,15 @@ public class MediaControlPanelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun bindSemanticActions() {
|
||||
val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
|
||||
val icon = context.getDrawable(android.R.drawable.ic_media_play)
|
||||
val bg = context.getDrawable(R.drawable.qs_media_round_button_background)
|
||||
val semanticActions = MediaButton(
|
||||
playOrPause = MediaAction(icon, Runnable {}, "play"),
|
||||
nextOrCustom = MediaAction(icon, Runnable {}, "next"),
|
||||
custom0 = MediaAction(icon, null, "custom 0"),
|
||||
custom1 = MediaAction(icon, null, "custom 1")
|
||||
playOrPause = MediaAction(icon, Runnable {}, "play", bg),
|
||||
nextOrCustom = MediaAction(icon, Runnable {}, "next", bg),
|
||||
custom0 = MediaAction(icon, null, "custom 0", bg),
|
||||
custom1 = MediaAction(icon, null, "custom 1", bg)
|
||||
)
|
||||
val state = mediaData.copy(semanticActions = semanticActions)
|
||||
|
||||
player.attachPlayer(viewHolder)
|
||||
player.bindPlayer(state, PACKAGE)
|
||||
|
||||
@@ -338,10 +340,10 @@ public class MediaControlPanelTest : SysuiTestCase() {
|
||||
fun bind_seekBarDisabled_seekBarVisibilityIsSetToInvisible() {
|
||||
whenever(seekBarViewModel.getEnabled()).thenReturn(false)
|
||||
|
||||
val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
|
||||
val icon = context.getDrawable(android.R.drawable.ic_media_play)
|
||||
val semanticActions = MediaButton(
|
||||
playOrPause = MediaAction(icon, Runnable {}, "play"),
|
||||
nextOrCustom = MediaAction(icon, Runnable {}, "next")
|
||||
playOrPause = MediaAction(icon, Runnable {}, "play", null),
|
||||
nextOrCustom = MediaAction(icon, Runnable {}, "next", null)
|
||||
)
|
||||
val state = mediaData.copy(semanticActions = semanticActions)
|
||||
|
||||
@@ -365,13 +367,14 @@ public class MediaControlPanelTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun bindNotificationActions() {
|
||||
val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
|
||||
val icon = context.getDrawable(android.R.drawable.ic_media_play)
|
||||
val bg = context.getDrawable(R.drawable.qs_media_round_button_background)
|
||||
val actions = listOf(
|
||||
MediaAction(icon, Runnable {}, "previous"),
|
||||
MediaAction(icon, Runnable {}, "play"),
|
||||
MediaAction(icon, null, "next"),
|
||||
MediaAction(icon, null, "custom 0"),
|
||||
MediaAction(icon, Runnable {}, "custom 1")
|
||||
MediaAction(icon, Runnable {}, "previous", bg),
|
||||
MediaAction(icon, Runnable {}, "play", bg),
|
||||
MediaAction(icon, null, "next", bg),
|
||||
MediaAction(icon, null, "custom 0", bg),
|
||||
MediaAction(icon, Runnable {}, "custom 1", bg)
|
||||
)
|
||||
val state = mediaData.copy(actions = actions,
|
||||
actionsToShowInCompact = listOf(1, 2),
|
||||
@@ -412,6 +415,72 @@ public class MediaControlPanelTest : SysuiTestCase() {
|
||||
verify(collapsedSet).setVisibility(R.id.action4, ConstraintSet.GONE)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun bindAnimatedSemanticActions() {
|
||||
val mockAvd0 = mock(AnimatedVectorDrawable::class.java)
|
||||
val mockAvd1 = mock(AnimatedVectorDrawable::class.java)
|
||||
val mockAvd2 = mock(AnimatedVectorDrawable::class.java)
|
||||
whenever(mockAvd0.mutate()).thenReturn(mockAvd0)
|
||||
whenever(mockAvd1.mutate()).thenReturn(mockAvd1)
|
||||
whenever(mockAvd2.mutate()).thenReturn(mockAvd2)
|
||||
|
||||
val icon = context.getDrawable(R.drawable.ic_media_play)
|
||||
val bg = context.getDrawable(R.drawable.ic_media_play_container)
|
||||
val semanticActions0 = MediaButton(
|
||||
playOrPause = MediaAction(mockAvd0, Runnable {}, "play", null))
|
||||
val semanticActions1 = MediaButton(
|
||||
playOrPause = MediaAction(mockAvd1, Runnable {}, "pause", null))
|
||||
val semanticActions2 = MediaButton(
|
||||
playOrPause = MediaAction(mockAvd2, Runnable {}, "loading", null))
|
||||
val state0 = mediaData.copy(semanticActions = semanticActions0)
|
||||
val state1 = mediaData.copy(semanticActions = semanticActions1)
|
||||
val state2 = mediaData.copy(semanticActions = semanticActions2)
|
||||
|
||||
player.attachPlayer(viewHolder)
|
||||
player.bindPlayer(state0, PACKAGE)
|
||||
|
||||
// Validate first binding
|
||||
assertThat(actionPlayPause.isEnabled()).isTrue()
|
||||
assertThat(actionPlayPause.contentDescription).isEqualTo("play")
|
||||
verify(collapsedSet).setVisibility(R.id.actionPlayPause, ConstraintSet.VISIBLE)
|
||||
assertThat(actionPlayPause.hasOnClickListeners()).isTrue()
|
||||
|
||||
// Trigger animation & update mock
|
||||
actionPlayPause.performClick()
|
||||
verify(mockAvd0, times(1)).start()
|
||||
whenever(mockAvd0.isRunning()).thenReturn(true)
|
||||
|
||||
// Validate states no longer bind
|
||||
player.bindPlayer(state1, PACKAGE)
|
||||
player.bindPlayer(state2, PACKAGE)
|
||||
assertThat(actionPlayPause.contentDescription).isEqualTo("play")
|
||||
|
||||
// Complete animation and run callbacks
|
||||
whenever(mockAvd0.isRunning()).thenReturn(false)
|
||||
val captor = ArgumentCaptor.forClass(Animatable2.AnimationCallback::class.java)
|
||||
verify(mockAvd0, times(1)).registerAnimationCallback(captor.capture())
|
||||
verify(mockAvd1, never())
|
||||
.registerAnimationCallback(any(Animatable2.AnimationCallback::class.java))
|
||||
verify(mockAvd2, never())
|
||||
.registerAnimationCallback(any(Animatable2.AnimationCallback::class.java))
|
||||
captor.getValue().onAnimationEnd(mockAvd0)
|
||||
|
||||
// Validate correct state was bound
|
||||
assertThat(actionPlayPause.contentDescription).isEqualTo("loading")
|
||||
verify(mockAvd0, times(1))
|
||||
.registerAnimationCallback(any(Animatable2.AnimationCallback::class.java))
|
||||
verify(mockAvd1, times(1)
|
||||
).registerAnimationCallback(any(Animatable2.AnimationCallback::class.java))
|
||||
verify(mockAvd2, times(1))
|
||||
.registerAnimationCallback(any(Animatable2.AnimationCallback::class.java))
|
||||
verify(mockAvd0, times(1))
|
||||
.unregisterAnimationCallback(any(Animatable2.AnimationCallback::class.java))
|
||||
verify(mockAvd1, times(1))
|
||||
.unregisterAnimationCallback(any(Animatable2.AnimationCallback::class.java))
|
||||
verify(mockAvd2, never())
|
||||
.unregisterAnimationCallback(any(Animatable2.AnimationCallback::class.java))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun bindText() {
|
||||
player.attachPlayer(viewHolder)
|
||||
|
||||
Reference in New Issue
Block a user