summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/Util.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogSeekBarAccessibilityDelegate.kt55
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/volume/UtilTest.java56
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java2
5 files changed, 153 insertions, 19 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Util.java b/packages/SystemUI/src/com/android/systemui/volume/Util.java
index 7edb5a55a9ae..df19013ce2c6 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Util.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Util.java
@@ -17,6 +17,7 @@
package com.android.systemui.volume;
import android.media.AudioManager;
+import android.util.MathUtils;
import android.view.View;
/**
@@ -46,4 +47,27 @@ class Util extends com.android.settingslib.volume.Util {
if (v == null || (v.getVisibility() == View.VISIBLE) == vis) return;
v.setVisibility(vis ? View.VISIBLE : View.GONE);
}
+
+ /**
+ * Translates a value from one range to another.
+ *
+ * ```
+ * Given: currentValue=3, currentRange=[0, 8], targetRange=[0, 100]
+ * Result: 37.5
+ * ```
+ */
+ public static float translateToRange(float value,
+ float valueRangeStart,
+ float valueRangeEnd,
+ float targetRangeStart,
+ float targetRangeEnd) {
+ float currentRangeLength = valueRangeEnd - valueRangeStart;
+ float targetRangeLength = targetRangeEnd - targetRangeStart;
+ if (currentRangeLength == 0f || targetRangeLength == 0f) {
+ return targetRangeStart;
+ }
+ float valueFraction = (value - valueRangeStart) / currentRangeLength;
+ return MathUtils.constrain(targetRangeStart + valueFraction * targetRangeLength,
+ targetRangeStart, targetRangeEnd);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 1688b0b51b41..22455417b647 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -137,13 +137,13 @@ import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.volume.domain.interactor.VolumePanelNavigationInteractor;
import com.android.systemui.volume.ui.navigation.VolumeNavigator;
-import dagger.Lazy;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
+import dagger.Lazy;
+
/**
* Visual presentation of the volume dialog.
*
@@ -166,6 +166,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
private static final int DRAWER_ANIMATION_DURATION_SHORT = 175;
private static final int DRAWER_ANIMATION_DURATION = 250;
+ private static final int DISPLAY_RANGE_MULTIPLIER = 100;
/** Shows volume dialog show animation. */
private static final String TYPE_SHOW = "show";
@@ -826,12 +827,14 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
writer.print(" mSilentMode: "); writer.println(mSilentMode);
}
- private static int getImpliedLevel(SeekBar seekBar, int progress) {
- final int m = seekBar.getMax();
- final int n = m / 100 - 1;
- final int level = progress == 0 ? 0
- : progress == m ? (m / 100) : (1 + (int) ((progress / (float) m) * n));
- return level;
+ private static int getVolumeFromProgress(StreamState state, SeekBar seekBar, int progress) {
+ return (int) Util.translateToRange(progress, seekBar.getMin(), seekBar.getMax(),
+ state.levelMin, state.levelMax);
+ }
+
+ private static int getProgressFromVolume(StreamState state, SeekBar seekBar, int volume) {
+ return (int) Util.translateToRange(volume, state.levelMin, state.levelMax, seekBar.getMin(),
+ seekBar.getMax());
}
@SuppressLint("InflateParams")
@@ -854,6 +857,8 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
addSliderHapticsToRow(row);
row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row));
row.number = row.view.findViewById(R.id.volume_number);
+ row.slider.setAccessibilityDelegate(
+ new VolumeDialogSeekBarAccessibilityDelegate(DISPLAY_RANGE_MULTIPLIER));
row.anim = null;
@@ -1916,12 +1921,12 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
: false;
// update slider max
- final int max = ss.levelMax * 100;
+ final int max = ss.levelMax * DISPLAY_RANGE_MULTIPLIER;
if (max != row.slider.getMax()) {
row.slider.setMax(max);
}
// update slider min
- final int min = ss.levelMin * 100;
+ final int min = ss.levelMin * DISPLAY_RANGE_MULTIPLIER;
if (min != row.slider.getMin()) {
row.slider.setMin(min);
}
@@ -2069,7 +2074,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
return; // don't update if user is sliding
}
final int progress = row.slider.getProgress();
- final int level = getImpliedLevel(row.slider, progress);
+ final int level = getVolumeFromProgress(row.ss, row.slider, progress);
final boolean rowVisible = row.view.getVisibility() == VISIBLE;
final boolean inGracePeriod = (SystemClock.uptimeMillis() - row.userAttempt)
< USER_ATTEMPT_GRACE_PERIOD;
@@ -2085,7 +2090,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
return; // don't clamp if visible
}
}
- final int newProgress = vlevel * 100;
+ final int newProgress = getProgressFromVolume(row.ss, row.slider, vlevel);
if (progress != newProgress) {
if (mShowing && rowVisible) {
// animate!
@@ -2530,13 +2535,13 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
+ " onProgressChanged " + progress + " fromUser=" + fromUser);
if (!fromUser) return;
if (mRow.ss.levelMin > 0) {
- final int minProgress = mRow.ss.levelMin * 100;
+ final int minProgress = getProgressFromVolume(mRow.ss, seekBar, mRow.ss.levelMin);
if (progress < minProgress) {
seekBar.setProgress(minProgress);
progress = minProgress;
}
}
- final int userLevel = getImpliedLevel(seekBar, progress);
+ final int userLevel = getVolumeFromProgress(mRow.ss, seekBar, progress);
if (mRow.ss.level != userLevel || mRow.ss.muted && userLevel > 0) {
mRow.userAttempt = SystemClock.uptimeMillis();
if (mRow.requestedLevel != userLevel) {
@@ -2569,7 +2574,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
}
mRow.tracking = false;
mRow.userAttempt = SystemClock.uptimeMillis();
- final int userLevel = getImpliedLevel(seekBar, seekBar.getProgress());
+ final int userLevel = getVolumeFromProgress(mRow.ss, seekBar, seekBar.getProgress());
Events.writeEvent(Events.EVENT_TOUCH_LEVEL_DONE, mRow.stream, userLevel);
if (mRow.ss.level != userLevel) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(H.RECHECK, mRow),
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogSeekBarAccessibilityDelegate.kt b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogSeekBarAccessibilityDelegate.kt
new file mode 100644
index 000000000000..cd31a9531db6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogSeekBarAccessibilityDelegate.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume
+
+import android.os.Bundle
+import android.view.View
+import android.view.View.AccessibilityDelegate
+import android.view.accessibility.AccessibilityNodeInfo
+import android.widget.SeekBar
+import com.android.internal.R
+
+class VolumeDialogSeekBarAccessibilityDelegate(
+ private val accessibilityStep: Int,
+) : AccessibilityDelegate() {
+
+ override fun performAccessibilityAction(host: View, action: Int, args: Bundle?): Boolean {
+ require(host is SeekBar) { "This class only works with the SeekBar" }
+ val seekBar: SeekBar = host
+ if (
+ action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD ||
+ action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD
+ ) {
+ var increment = accessibilityStep
+ if (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) {
+ increment = -increment
+ }
+
+ return super.performAccessibilityAction(
+ host,
+ R.id.accessibilityActionSetProgress,
+ Bundle().apply {
+ putFloat(
+ AccessibilityNodeInfo.ACTION_ARGUMENT_PROGRESS_VALUE,
+ (seekBar.progress + increment).coerceIn(seekBar.min, seekBar.max).toFloat(),
+ )
+ },
+ )
+ }
+ return super.performAccessibilityAction(host, action, args)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/UtilTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/UtilTest.java
index fb82b8fed76c..483dc0c9c974 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/UtilTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/UtilTest.java
@@ -15,14 +15,14 @@
*/
package com.android.systemui.volume;
+import static com.google.common.truth.Truth.assertThat;
+
import android.media.MediaMetadata;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import junit.framework.Assert;
-
import org.junit.Test;
@SmallTest
@@ -30,11 +30,59 @@ public class UtilTest extends SysuiTestCase {
@Test
public void testMediaMetadataToString_null() {
- Assert.assertEquals(null, Util.mediaMetadataToString(null));
+ assertThat(Util.mediaMetadataToString(null)).isNull();
}
@Test
public void testMediaMetadataToString_notNull() {
- Assert.assertNotNull(Util.mediaMetadataToString(new MediaMetadata.Builder().build()));
+ assertThat(Util.mediaMetadataToString(new MediaMetadata.Builder().build())).isNotNull();
+ }
+
+ @Test
+ public void translateToRange_translatesStartToStart() {
+ assertThat(
+ (int) Util.translateToRange(
+ /* value= */ 0,
+ /* valueRangeStart= */ 0,
+ /* valueRangeEnd= */ 7,
+ /* targetRangeStart= */ 0,
+ /* targetRangeEnd= */700)
+ ).isEqualTo(0);
+ }
+
+ @Test
+ public void translateToRange_translatesValueToValue() {
+ assertThat(
+ (int) Util.translateToRange(
+ /* value= */ 4,
+ /* valueRangeStart= */ 0,
+ /* valueRangeEnd= */ 7,
+ /* targetRangeStart= */ 0,
+ /* targetRangeEnd= */700)
+ ).isEqualTo(400);
+ }
+
+ @Test
+ public void translateToRange_translatesEndToEnd() {
+ assertThat(
+ (int) Util.translateToRange(
+ /* value= */ 7,
+ /* valueRangeStart= */ 0,
+ /* valueRangeEnd= */ 7,
+ /* targetRangeStart= */ 0,
+ /* targetRangeEnd= */700)
+ ).isEqualTo(700);
+ }
+
+ @Test
+ public void translateToRange_returnsStartForEmptyRange() {
+ assertThat(
+ (int) Util.translateToRange(
+ /* value= */ 7,
+ /* valueRangeStart= */ 7,
+ /* valueRangeEnd= */ 7,
+ /* targetRangeStart= */ 700,
+ /* targetRangeEnd= */700)
+ ).isEqualTo(700);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index ed2fb2c0cfc9..3b468aa011ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -248,6 +248,8 @@ public class VolumeDialogImplTest extends SysuiTestCase {
VolumeDialogController.StreamState ss = new VolumeDialogController.StreamState();
ss.name = STREAMS.get(i);
ss.level = 1;
+ ss.levelMin = 0;
+ ss.levelMax = 25;
state.states.append(i, ss);
}
return state;