Make seek bar support direct manipulation mode
And update the background of seekbar thumb to support direct
manipulation mode, including:
1. Rename the existing seekbar_background to seekbar_progress
2. Create a new seekbar_background and set it as the seekbar's
background
3. Update the seekbar_thumb so that it can draw 2 rings around the thumb
when the seekbar is selected
4. Use media source color to set the color of the thumb, excluding the
color of the 2 rings around the thumb
Bug: 161483857
Test: manual
Change-Id: I183b5c803e9e6638e73735761128182019c4b697
diff --git a/res/color/progress_bar_thumb_inner_ring_color.xml b/res/color/progress_bar_thumb_inner_ring_color.xml
new file mode 100644
index 0000000..d3a9d4e
--- /dev/null
+++ b/res/color/progress_bar_thumb_inner_ring_color.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_selected="true" android:color="@color/car_ui_rotary_focus_fill_color"/>
+ <item android:color="@android:color/transparent"/>
+</selector>
diff --git a/res/color/progress_bar_thumb_outer_ring_color.xml b/res/color/progress_bar_thumb_outer_ring_color.xml
new file mode 100644
index 0000000..1bc1926
--- /dev/null
+++ b/res/color/progress_bar_thumb_outer_ring_color.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_selected="true" android:color="@color/car_ui_rotary_focus_stroke_color"/>
+ <item android:color="@android:color/transparent"/>
+</selector>
diff --git a/res/drawable/seekbar_foreground.xml b/res/drawable/seekbar_foreground.xml
new file mode 100644
index 0000000..3942e21
--- /dev/null
+++ b/res/drawable/seekbar_foreground.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2020, The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- SeekBar highlight is drawn when it's focused but not in direct manipulation mode. When
+ in direct manipulation mode (android:state_selected="true"), the highlight is drawn on
+ the thumb instead. -->
+ <item android:state_selected="false" android:state_focused="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/car_ui_rotary_focus_fill_color"/>
+ <stroke android:width="@dimen/car_ui_rotary_focus_stroke_width"
+ android:color="@color/car_ui_rotary_focus_stroke_color"/>
+ </shape>
+ </item>
+</selector>
diff --git a/res/drawable/seekbar_background.xml b/res/drawable/seekbar_progress.xml
similarity index 95%
rename from res/drawable/seekbar_background.xml
rename to res/drawable/seekbar_progress.xml
index ec08455..3e68a73 100644
--- a/res/drawable/seekbar_background.xml
+++ b/res/drawable/seekbar_progress.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2016, The Android Open Source Project
+ Copyright 2020, The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/res/drawable/seekbar_thumb.xml b/res/drawable/seekbar_thumb.xml
index 1d0b4a1..eb0c253 100644
--- a/res/drawable/seekbar_thumb.xml
+++ b/res/drawable/seekbar_thumb.xml
@@ -14,10 +14,28 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval">
- <solid android:color="@color/progress_bar_thumb_color"/>
- <size
- android:width="@dimen/playback_seekbar_thumb_width"
- android:height="@dimen/playback_seekbar_thumb_height"/>
-</shape>
\ No newline at end of file
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/thumb_center">
+ <shape android:shape="oval">
+ <solid android:color="@color/progress_bar_thumb_color"/>
+ <size android:width="@dimen/playback_seekbar_thumb_width"
+ android:height="@dimen/playback_seekbar_thumb_height"/>
+ </shape>
+ </item>
+ <item>
+ <shape android:shape="ring"
+ android:innerRadius="@dimen/playback_seekbar_thumb_inner_ring_inner_radius"
+ android:thickness="@dimen/playback_seekbar_thumb_inner_ring_thickness"
+ android:useLevel="false">
+ <solid android:color="@color/progress_bar_thumb_inner_ring_color"/>
+ </shape>
+ </item>
+ <item>
+ <shape android:shape="ring"
+ android:innerRadius="@dimen/playback_seekbar_thumb_outer_ring_inner_radius"
+ android:thickness="@dimen/playback_seekbar_thumb_outer_ring_thickness"
+ android:useLevel="false">
+ <solid android:color="@color/progress_bar_thumb_outer_ring_color"/>
+ </shape>
+ </item>
+</layer-list>
diff --git a/res/layout/fragment_playback.xml b/res/layout/fragment_playback.xml
index 130eb1d..0c933ba 100644
--- a/res/layout/fragment_playback.xml
+++ b/res/layout/fragment_playback.xml
@@ -77,13 +77,13 @@
android:clickable="false"
android:paddingEnd="@dimen/playback_seekbar_padding_x"
android:paddingStart="@dimen/playback_seekbar_padding_x"
- android:progressDrawable="@drawable/seekbar_background"
+ android:progressDrawable="@drawable/seekbar_progress"
android:thumb="@drawable/seekbar_thumb"
android:thumbOffset="@dimen/playback_seekbar_thumb_offset"
android:splitTrack="false"
android:progressTint="@color/progress_bar_highlight"
android:progressBackgroundTint="@color/progress_bar_background"
- android:background="@null"/>
+ android:foreground="@drawable/seekbar_foreground"/>
</com.android.car.ui.FocusArea>
<Space
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index b667604..dbb6ab8 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -40,6 +40,10 @@
<!-- Size of the thumb in the playback seekbar -->
<dimen name="playback_seekbar_thumb_height">16dp</dimen>
<dimen name="playback_seekbar_thumb_width">16dp</dimen>
+ <dimen name="playback_seekbar_thumb_inner_ring_inner_radius">8dp</dimen>
+ <dimen name="playback_seekbar_thumb_inner_ring_thickness">8dp</dimen>
+ <dimen name="playback_seekbar_thumb_outer_ring_inner_radius">16dp</dimen>
+ <dimen name="playback_seekbar_thumb_outer_ring_thickness">8dp</dimen>
<dimen name="playback_seekbar_thumb_offset">0px</dimen>
<!-- Paddings of playback seekbar -->
<dimen name="playback_seekbar_padding_x">0dp</dimen>
diff --git a/src/com/android/car/media/PlaybackFragment.java b/src/com/android/car/media/PlaybackFragment.java
index afd0f72..0dbf7bd 100644
--- a/src/com/android/car/media/PlaybackFragment.java
+++ b/src/com/android/car/media/PlaybackFragment.java
@@ -21,8 +21,11 @@
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
+import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
import android.os.Bundle;
import android.util.Log;
import android.util.Size;
@@ -55,6 +58,7 @@
import com.android.car.ui.recyclerview.ScrollingLimitedViewHolder;
import com.android.car.ui.toolbar.MenuItem;
import com.android.car.ui.toolbar.Toolbar;
+import com.android.car.ui.utils.DirectManipulationHelper;
import com.android.car.uxr.LifeCycleObserverUxrContentLimiter;
import com.android.car.uxr.UxrContentLimiterImpl;
@@ -463,6 +467,7 @@
mQueue = view.findViewById(R.id.queue_list);
mSeekBarContainer = view.findViewById(R.id.seek_bar_container);
mSeekBar = view.findViewById(R.id.seek_bar);
+ DirectManipulationHelper.setSupportsRotateDirectly(mSeekBar, true);
mAppBarController = new AppBarController(view);
mAppBarController.setTitle(R.string.fragment_playback_title);
@@ -518,15 +523,13 @@
if (useMediaSourceColor) {
getPlaybackViewModel().getMediaSourceColors().observe(getViewLifecycleOwner(),
sourceColors -> {
- int color = sourceColors != null ? sourceColors.getAccentColor(
- defaultColor)
+ int color = sourceColors != null
+ ? sourceColors.getAccentColor(defaultColor)
: defaultColor;
- mSeekBar.setThumbTintList(ColorStateList.valueOf(color));
- mSeekBar.setProgressTintList(ColorStateList.valueOf(color));
+ setSeekBarColor(color);
});
} else {
- mSeekBar.setThumbTintList(ColorStateList.valueOf(defaultColor));
- mSeekBar.setProgressTintList(ColorStateList.valueOf(defaultColor));
+ setSeekBarColor(defaultColor);
}
} else {
mSeekBar.setVisibility(View.GONE);
@@ -759,6 +762,24 @@
return MediaSourceViewModel.get(getActivity().getApplication(), MEDIA_SOURCE_MODE_BROWSE);
}
+ private void setSeekBarColor(int color) {
+ mSeekBar.setProgressTintList(ColorStateList.valueOf(color));
+
+ // If the thumb drawable consists of a center drawable, only change the color of the center
+ // drawable. Otherwise change the color of the entire thumb drawable.
+ Drawable thumb = mSeekBar.getThumb();
+ if (thumb instanceof LayerDrawable) {
+ LayerDrawable thumbDrawable = (LayerDrawable) thumb;
+ Drawable thumbCenter = thumbDrawable.findDrawableByLayerId(R.id.thumb_center);
+ if (thumbCenter != null) {
+ thumbCenter.setColorFilter(color, PorterDuff.Mode.SRC);
+ thumbDrawable.setDrawableByLayerId(R.id.thumb_center, thumbCenter);
+ return;
+ }
+ }
+ mSeekBar.setThumbTintList(ColorStateList.valueOf(color));
+ }
+
/**
* Sets a listener of this PlaybackFragment events. In order to avoid memory leaks, consumers
* must reset this reference by setting the listener to null.