Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e3a12e85 authored by Philip Junker's avatar Philip Junker
Browse files

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
parent 891f69f4
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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
  }
+80 −2
Original line number Diff line number Diff line
@@ -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)}
 */
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);
    }
}
+19 −2
Original line number Diff line number Diff line
@@ -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:
+54 −0
Original line number Diff line number Diff line
/*
 * 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));
    }
}