Add support for navigation repeat sound effects

NO_TYPO_CHECK=Existing typo in getContantForFocusDirection (e.g. b/3170596)

Test: atest android.view.cts.SoundEffectConstantsTest
Test: atest android.view.SoundEffectConstantsTest
Bug: 157407957
Change-Id: I7377b1df6b151ea0d77476f0186b4bb21f1a55fe
This commit is contained in:
Philip Junker
2020-12-04 11:07:58 +01:00
parent 891f69f441
commit e3a12e85c4
4 changed files with 158 additions and 4 deletions

View File

@@ -48009,10 +48009,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
}

View File

@@ -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);
}
}

View File

@@ -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:

View File

@@ -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));
}
}