summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Philip Junker <philipjunker@google.com> 2021-02-25 14:03:14 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-02-25 14:03:14 +0000
commitdaeb58b5743fcdfcbe1eeb4ef687feb0b90f1524 (patch)
treeae86f14d2637f7f6b7b6bfe66202ff925e621242
parentda74086ba4adbaab2ee38ed7aa65e6a2f2c27268 (diff)
parente3a12e85c4aa75988738c6df18ffdcd4d2b2efb1 (diff)
Merge "Add support for navigation repeat sound effects" into sc-dev
-rw-r--r--core/api/current.txt5
-rw-r--r--core/java/android/view/SoundEffectConstants.java82
-rw-r--r--core/java/android/view/ViewRootImpl.java21
-rw-r--r--core/tests/coretests/src/android/view/SoundEffectConstantsTest.java54
4 files changed, 158 insertions, 4 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 08c7a43294c3..6b27567323d4 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -48034,10 +48034,15 @@ package android.view {
}
public class SoundEffectConstants {
+ method public static int getConstantForFocusDirection(int, boolean);
method public static int getContantForFocusDirection(int);
field public static final int CLICK = 0; // 0x0
field public static final int NAVIGATION_DOWN = 4; // 0x4
field public static final int NAVIGATION_LEFT = 1; // 0x1
+ field public static final int NAVIGATION_REPEAT_DOWN = 8; // 0x8
+ field public static final int NAVIGATION_REPEAT_LEFT = 5; // 0x5
+ field public static final int NAVIGATION_REPEAT_RIGHT = 7; // 0x7
+ field public static final int NAVIGATION_REPEAT_UP = 6; // 0x6
field public static final int NAVIGATION_RIGHT = 3; // 0x3
field public static final int NAVIGATION_UP = 2; // 0x2
}
diff --git a/core/java/android/view/SoundEffectConstants.java b/core/java/android/view/SoundEffectConstants.java
index 8d891bbc2cfc..f177451783dc 100644
--- a/core/java/android/view/SoundEffectConstants.java
+++ b/core/java/android/view/SoundEffectConstants.java
@@ -16,12 +16,21 @@
package android.view;
+import android.media.AudioManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import java.util.Random;
+
/**
- * Constants to be used to play sound effects via {@link View#playSoundEffect(int)}
+ * Constants to be used to play sound effects via {@link View#playSoundEffect(int)}
*/
public class SoundEffectConstants {
private SoundEffectConstants() {}
+ private static final Random NAVIGATION_REPEAT_RANDOMIZER = new Random();
+ private static int sLastNavigationRepeatSoundEffectId = -1;
public static final int CLICK = 0;
@@ -29,6 +38,14 @@ public class SoundEffectConstants {
public static final int NAVIGATION_UP = 2;
public static final int NAVIGATION_RIGHT = 3;
public static final int NAVIGATION_DOWN = 4;
+ /** Sound effect for a repeatedly triggered navigation, e.g. due to long pressing a button */
+ public static final int NAVIGATION_REPEAT_LEFT = 5;
+ /** @see #NAVIGATION_REPEAT_LEFT */
+ public static final int NAVIGATION_REPEAT_UP = 6;
+ /** @see #NAVIGATION_REPEAT_LEFT */
+ public static final int NAVIGATION_REPEAT_RIGHT = 7;
+ /** @see #NAVIGATION_REPEAT_LEFT */
+ public static final int NAVIGATION_REPEAT_DOWN = 8;
/**
* Get the sonification constant for the focus directions.
@@ -40,7 +57,7 @@ public class SoundEffectConstants {
* @throws {@link IllegalArgumentException} when the passed direction is not one of the
* documented values.
*/
- public static int getContantForFocusDirection(int direction) {
+ public static int getContantForFocusDirection(@View.FocusDirection int direction) {
switch (direction) {
case View.FOCUS_RIGHT:
return SoundEffectConstants.NAVIGATION_RIGHT;
@@ -56,4 +73,65 @@ public class SoundEffectConstants {
throw new IllegalArgumentException("direction must be one of "
+ "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, FOCUS_BACKWARD}.");
}
+
+ /**
+ * Get the sonification constant for the focus directions
+ * @param direction One of {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN},
+ * {@link View#FOCUS_LEFT}, {@link View#FOCUS_RIGHT}, {@link View#FOCUS_FORWARD}
+ * or {@link View#FOCUS_BACKWARD}
+ * @param repeating True if the user long-presses a direction
+ * @return The appropriate sonification constant
+ * @throws IllegalArgumentException when the passed direction is not one of the
+ * documented values.
+ */
+ public static int getConstantForFocusDirection(@View.FocusDirection int direction,
+ boolean repeating) {
+ if (repeating) {
+ switch (direction) {
+ case View.FOCUS_RIGHT:
+ return SoundEffectConstants.NAVIGATION_REPEAT_RIGHT;
+ case View.FOCUS_FORWARD:
+ case View.FOCUS_DOWN:
+ return SoundEffectConstants.NAVIGATION_REPEAT_DOWN;
+ case View.FOCUS_LEFT:
+ return SoundEffectConstants.NAVIGATION_REPEAT_LEFT;
+ case View.FOCUS_BACKWARD:
+ case View.FOCUS_UP:
+ return SoundEffectConstants.NAVIGATION_REPEAT_UP;
+ }
+ throw new IllegalArgumentException("direction must be one of {FOCUS_UP, FOCUS_DOWN, "
+ + "FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, FOCUS_BACKWARD}.");
+ } else {
+ return getContantForFocusDirection(direction);
+ }
+ }
+
+ /**
+ * @param effectId any of the effect ids defined in {@link SoundEffectConstants}
+ * @return true if the given effect id is a navigation repeat one
+ * @hide
+ */
+ @VisibleForTesting(visibility = Visibility.PACKAGE)
+ public static boolean isNavigationRepeat(int effectId) {
+ return effectId == SoundEffectConstants.NAVIGATION_REPEAT_DOWN
+ || effectId == SoundEffectConstants.NAVIGATION_REPEAT_LEFT
+ || effectId == SoundEffectConstants.NAVIGATION_REPEAT_RIGHT
+ || effectId == SoundEffectConstants.NAVIGATION_REPEAT_UP;
+ }
+
+ /**
+ * @return The next navigation repeat sound effect id, chosen at random in a non-repeating
+ * fashion
+ * @hide
+ */
+ @VisibleForTesting(visibility = Visibility.PACKAGE)
+ public static int nextNavigationRepeatSoundEffectId() {
+ int next = NAVIGATION_REPEAT_RANDOMIZER.nextInt(
+ AudioManager.NUM_NAVIGATION_REPEAT_SOUND_EFFECTS - 1);
+ if (next >= sLastNavigationRepeatSoundEffectId) {
+ next++;
+ }
+ sLastNavigationRepeatSoundEffectId = next;
+ return AudioManager.getNthNavigationRepeatSoundEffect(next);
+ }
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 144691d3eaa0..1abcb15ca7a3 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -323,6 +323,8 @@ public final class ViewRootImpl implements ViewParent,
private boolean mForceDisableBLAST;
private boolean mEnableTripleBuffering;
+ private boolean mFastScrollSoundEffectsEnabled;
+
/**
* Signals that compatibility booleans have been initialized according to
* target SDK versions.
@@ -813,6 +815,8 @@ public final class ViewRootImpl implements ViewParent,
loadSystemProperties();
mImeFocusController = new ImeFocusController(this);
+ AudioManager audioManager = mContext.getSystemService(AudioManager.class);
+ mFastScrollSoundEffectsEnabled = audioManager.areNavigationRepeatSoundEffectsEnabled();
}
public static void addFirstDrawHandler(Runnable callback) {
@@ -6081,8 +6085,10 @@ public final class ViewRootImpl implements ViewParent,
v, mTempRect);
}
if (v.requestFocus(direction, mTempRect)) {
- playSoundEffect(SoundEffectConstants
- .getContantForFocusDirection(direction));
+ boolean isFastScrolling = event.getRepeatCount() > 0;
+ playSoundEffect(
+ SoundEffectConstants.getConstantForFocusDirection(direction,
+ isFastScrolling));
return true;
}
}
@@ -7743,20 +7749,31 @@ public final class ViewRootImpl implements ViewParent,
try {
final AudioManager audioManager = getAudioManager();
+ if (mFastScrollSoundEffectsEnabled
+ && SoundEffectConstants.isNavigationRepeat(effectId)) {
+ audioManager.playSoundEffect(
+ SoundEffectConstants.nextNavigationRepeatSoundEffectId());
+ return;
+ }
+
switch (effectId) {
case SoundEffectConstants.CLICK:
audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
return;
case SoundEffectConstants.NAVIGATION_DOWN:
+ case SoundEffectConstants.NAVIGATION_REPEAT_DOWN:
audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
return;
case SoundEffectConstants.NAVIGATION_LEFT:
+ case SoundEffectConstants.NAVIGATION_REPEAT_LEFT:
audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
return;
case SoundEffectConstants.NAVIGATION_RIGHT:
+ case SoundEffectConstants.NAVIGATION_REPEAT_RIGHT:
audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
return;
case SoundEffectConstants.NAVIGATION_UP:
+ case SoundEffectConstants.NAVIGATION_REPEAT_UP:
audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
return;
default:
diff --git a/core/tests/coretests/src/android/view/SoundEffectConstantsTest.java b/core/tests/coretests/src/android/view/SoundEffectConstantsTest.java
new file mode 100644
index 000000000000..45ffb1221515
--- /dev/null
+++ b/core/tests/coretests/src/android/view/SoundEffectConstantsTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 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 android.view;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link SoundEffectConstants}
+ *
+ * Build/Install/Run:
+ * atest FrameworksCoreTests:SoundEffectConstantsTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SoundEffectConstantsTest {
+
+ @Test
+ public void testIsNavigationRepeat() {
+ assertTrue(SoundEffectConstants.isNavigationRepeat(
+ SoundEffectConstants.NAVIGATION_REPEAT_RIGHT));
+ assertTrue(SoundEffectConstants.isNavigationRepeat(
+ SoundEffectConstants.NAVIGATION_REPEAT_LEFT));
+ assertTrue(
+ SoundEffectConstants.isNavigationRepeat(SoundEffectConstants.NAVIGATION_REPEAT_UP));
+ assertTrue(SoundEffectConstants.isNavigationRepeat(
+ SoundEffectConstants.NAVIGATION_REPEAT_DOWN));
+ assertFalse(SoundEffectConstants.isNavigationRepeat(SoundEffectConstants.NAVIGATION_RIGHT));
+ assertFalse(SoundEffectConstants.isNavigationRepeat(SoundEffectConstants.NAVIGATION_LEFT));
+ assertFalse(SoundEffectConstants.isNavigationRepeat(SoundEffectConstants.NAVIGATION_UP));
+ assertFalse(SoundEffectConstants.isNavigationRepeat(SoundEffectConstants.NAVIGATION_DOWN));
+ assertFalse(SoundEffectConstants.isNavigationRepeat(-1));
+ }
+}