diff options
| author | 2021-02-25 14:03:14 +0000 | |
|---|---|---|
| committer | 2021-02-25 14:03:14 +0000 | |
| commit | daeb58b5743fcdfcbe1eeb4ef687feb0b90f1524 (patch) | |
| tree | ae86f14d2637f7f6b7b6bfe66202ff925e621242 | |
| parent | da74086ba4adbaab2ee38ed7aa65e6a2f2c27268 (diff) | |
| parent | e3a12e85c4aa75988738c6df18ffdcd4d2b2efb1 (diff) | |
Merge "Add support for navigation repeat sound effects" into sc-dev
| -rw-r--r-- | core/api/current.txt | 5 | ||||
| -rw-r--r-- | core/java/android/view/SoundEffectConstants.java | 82 | ||||
| -rw-r--r-- | core/java/android/view/ViewRootImpl.java | 21 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/view/SoundEffectConstantsTest.java | 54 |
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)); + } +} |