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

Commit 4fd76391 authored by Juan Sebastian Martinez's avatar Juan Sebastian Martinez
Browse files

Adding the MSDLPlayer with haptics-only capabilities

The player and its implementation are added to play HapticCompositions.
The HapticHelper abstraction is added as a single point of integration
with the framework APIs with respect to haptics.

Test: atest msdl_tests
Flag: NONE usage of the API will be flagged by its use case
Bug: 344654090

Change-Id: Ib6e8139ef4131a3a1f180d7a76f1df4ec4e0bfcb
parent 994100e4
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -21,9 +21,10 @@ android_library {
    name: "msdl",
    manifest: "AndroidManifest.xml",
    sdk_version: "system_current",
    min_sdk_version: "31",
    min_sdk_version: "33",
    static_libs: [
        "kotlinx_coroutines_android",
        "androidx.annotation_annotation",
    ],
    srcs: [
        "src/**/*.java",
+2 −1
Original line number Diff line number Diff line
@@ -17,4 +17,5 @@

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.google.android.msdl">
  <uses-permission android:name="android.permission.VIBRATE" />
</manifest>
+163 −0
Original line number Diff line number Diff line
/*
 * 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.google.android.msdl.data.model

/** System-level tokens defined in the Multi-sensory Design Language (MSDL) */
enum class MSDLToken(
    val hapticToken: HapticToken,
    val soundToken: SoundToken,
    val minimumFeedbackLevel: FeedbackLevel,
) {
    /* Inform the user with emphasis that their current action FAILED to complete */
    FAILURE_HIGH_EMPHASIS(
        HapticToken.NEGATIVE_CONFIRMATION_HIGH_EMPHASIS,
        SoundToken.FAILURE_HIGH_EMPHASIS,
        FeedbackLevel.MINIMAL,
    ),
    /* Inform the user that their current action FAILED to complete */
    FAILURE(
        HapticToken.NEGATIVE_CONFIRMATION_MEDIUM_EMPHASIS,
        SoundToken.FAILURE,
        FeedbackLevel.MINIMAL,
    ),
    /* Inform the user their current action was completed SUCCESSFULLY */
    SUCCESS(
        HapticToken.POSITIVE_CONFIRMATION_HIGH_EMPHASIS,
        SoundToken.SUCCESS,
        FeedbackLevel.MINIMAL,
    ),
    /* Inform the user that an ongoing activity has started */
    START(
        HapticToken.NEUTRAL_CONFIRMATION_HIGH_EMPHASIS,
        SoundToken.START,
        FeedbackLevel.DEFAULT,
    ),
    /* Inform the user that their previously started activity has stopped SUCCESSFULLY */
    STOP(
        HapticToken.POSITIVE_CONFIRMATION_MEDIUM_EMPHASIS,
        SoundToken.STOP,
        FeedbackLevel.DEFAULT,
    ),
    /* Inform the user that the state of an interactive component has been switched to on SUCCESSFULLY */
    SWITCH_ON(
        HapticToken.POSITIVE_CONFIRMATION_MEDIUM_EMPHASIS,
        SoundToken.SWITCH_ON,
        FeedbackLevel.DEFAULT,
    ),
    /* Inform the user that the state of an interactive component has been switched to off SUCCESSFULLY */
    SWITCH_OFF(
        HapticToken.POSITIVE_CONFIRMATION_MEDIUM_EMPHASIS,
        SoundToken.SWITCH_OFF,
        FeedbackLevel.DEFAULT,
    ),
    /* Inform the user the state of their device changed to unlocked SUCCESSFULLY */
    UNLOCK(
        HapticToken.POSITIVE_CONFIRMATION_LOW_EMPHASIS,
        SoundToken.UNLOCK,
        FeedbackLevel.DEFAULT,
    ),
    /* Inform the user the state of their device changed to locked SUCCESSFULLY */
    LOCK(
        HapticToken.POSITIVE_CONFIRMATION_LOW_EMPHASIS,
        SoundToken.LOCK,
        FeedbackLevel.DEFAULT,
    ),
    /* Inform the user that their long-press gesture has resulted in the revealing of more contextual information */
    LONG_PRESS(
        HapticToken.LONG_PRESS,
        SoundToken.LONG_PRESS,
        FeedbackLevel.MINIMAL,
    ),
    /* Inform the user that their swipe gesture has reached a threshold that confirms navigation or the reveal of additional information. */
    SWIPE_THRESHOLD_INDICATOR(
        HapticToken.SWIPE_THRESHOLD_INDICATOR,
        SoundToken.SWIPE_THRESHOLD_INDICATOR,
        FeedbackLevel.MINIMAL,
    ),
    /* Played when the user taps on a high-emphasis UI element */
    TAP_HIGH_EMPHASIS(
        HapticToken.TAP_HIGH_EMPHASIS,
        SoundToken.TAP_HIGH_EMPHASIS,
        FeedbackLevel.EXPRESSIVE,
    ),
    /* Inform the user that their tap has resulted in a selection */
    TAP_MEDIUM_EMPHASIS(
        HapticToken.TAP_MEDIUM_EMPHASIS,
        SoundToken.TAP_MEDIUM_EMPHASIS,
        FeedbackLevel.DEFAULT,
    ),
    /* Played when a users drag gesture reaches the maximum value */
    DRAG_THRESHOLD_INDICATOR_CEILING(
        HapticToken.DRAG_THRESHOLD_INDICATOR,
        SoundToken.DRAG_THRESHOLD_INDICATOR_CEILING,
        FeedbackLevel.DEFAULT,
    ),
    /* Played when a users drag gesture reaches the minimum value */
    DRAG_THRESHOLD_INDICATOR_FLOOR(
        HapticToken.DRAG_THRESHOLD_INDICATOR,
        SoundToken.DRAG_THRESHOLD_INDICATOR_FLOOR,
        FeedbackLevel.DEFAULT,
    ),
    /* Inform the user that their drag gesture has resulted in an incremental value change.
     * For usage in haptic sliders, this token can be played along with
     * [InteractionProperties.DynamicVibrationScale] properties to control haptic scaling as a
     * function of position and velocity.
     */
    DRAG_INDICATOR(
        HapticToken.DRAG_INDICATOR,
        SoundToken.DRAG_INDICATOR,
        FeedbackLevel.DEFAULT,
    ),
    /* Played when a user taps on any UI element that can be interacted with but is not otherwise defined */
    TAP_LOW_EMPHASIS(
        HapticToken.TAP_LOW_EMPHASIS,
        SoundToken.TAP_LOW_EMPHASIS,
        FeedbackLevel.EXPRESSIVE,
    ),
    /* Played when the user touches a key on the keyboard that is otherwise undefined */
    KEYPRESS_STANDARD(
        HapticToken.KEYPRESS_STANDARD,
        SoundToken.KEYPRESS_STANDARD,
        FeedbackLevel.DEFAULT,
    ),
    /* Played when the user touches the space key */
    KEYPRESS_SPACEBAR(
        HapticToken.KEYPRESS_SPACEBAR,
        SoundToken.KEYPRESS_SPACEBAR,
        FeedbackLevel.DEFAULT,
    ),
    /* Played when the user touches the return key */
    KEYPRESS_RETURN(
        HapticToken.KEYPRESS_RETURN,
        SoundToken.KEYPRESS_RETURN,
        FeedbackLevel.DEFAULT,
    ),
    /* Played when the user touches the delete key */
    KEYPRESS_DELETE(
        HapticToken.KEYPRESS_DELETE,
        SoundToken.KEYPRESS_DELETE,
        FeedbackLevel.DEFAULT,
    ),
}

/** Level of feedback that contains a token */
enum class FeedbackLevel {
    NO_FEEDBACK,
    MINIMAL,
    DEFAULT,
    EXPRESSIVE,
}
+11 −4
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ interface MSDLRepository {
     * @param[hapticToken] The [HapticToken] that points to the data.
     * @return the data that corresponds to the token at the time this function is called.
     */
    fun getHapticData(hapticToken: HapticToken): MSDLData?
    fun getHapticData(hapticToken: HapticToken): MSDLHapticData?

    /**
     * Get the [MSDLData] that corresponds to the given sound reference token. This function needs
@@ -46,12 +46,19 @@ interface MSDLRepository {
     * @param[soundToken] The [SoundToken] that points to the data.
     * @return the data that corresponds to the token at the time this function is called.
     */
    fun getAudioData(soundToken: SoundToken): MSDLData?
    fun getAudioData(soundToken: SoundToken): MSDLSoundData?
}

/** Representation of data contained in a [MSDLRepository] */
fun interface MSDLData {
fun interface MSDLHapticData {

    /** Retrieve the data */
    /** Retrieve the haptic data */
    fun get(): Any?
}

/** Representation of data contained in a [MSDLRepository] */
fun interface MSDLSoundData {

    /** Retrieve the sound data */
    fun get(): Any?
}
+20 −20
Original line number Diff line number Diff line
@@ -25,20 +25,20 @@ import com.google.android.msdl.data.model.SoundToken
/** A [MSDLRepository] that holds haptic compositions as haptic data. */
class MSDLRepositoryImpl : MSDLRepository {

    override fun getAudioData(soundToken: SoundToken): MSDLData? {
    override fun getAudioData(soundToken: SoundToken): MSDLSoundData? {
        // TODO(b/345248875) Implement a caching strategy in accordance to the audio file strategy
        return null
    }

    override fun getHapticData(hapticToken: HapticToken): MSDLData? = HAPTIC_DATA[hapticToken]
    override fun getHapticData(hapticToken: HapticToken): MSDLHapticData? = HAPTIC_DATA[hapticToken]

    companion object {
        private val HAPTIC_DATA: Map<HapticToken, MSDLData> =
        private val HAPTIC_DATA: Map<HapticToken, MSDLHapticData> =
            mapOf(
                HapticToken.NEGATIVE_CONFIRMATION_HIGH_EMPHASIS to
                    MSDLData { HapticComposition(null) },
                    MSDLHapticData { HapticComposition(null) },
                HapticToken.NEGATIVE_CONFIRMATION_MEDIUM_EMPHASIS to
                    MSDLData {
                    MSDLHapticData {
                        HapticComposition(
                            listOf(
                                HapticCompositionPrimitive(
@@ -60,7 +60,7 @@ class MSDLRepositoryImpl : MSDLRepository {
                        )
                    },
                HapticToken.POSITIVE_CONFIRMATION_HIGH_EMPHASIS to
                    MSDLData {
                    MSDLHapticData {
                        HapticComposition(
                            listOf(
                                HapticCompositionPrimitive(
@@ -77,7 +77,7 @@ class MSDLRepositoryImpl : MSDLRepository {
                        )
                    },
                HapticToken.POSITIVE_CONFIRMATION_MEDIUM_EMPHASIS to
                    MSDLData {
                    MSDLHapticData {
                        HapticComposition(
                            listOf(
                                HapticCompositionPrimitive(
@@ -94,7 +94,7 @@ class MSDLRepositoryImpl : MSDLRepository {
                        )
                    },
                HapticToken.POSITIVE_CONFIRMATION_LOW_EMPHASIS to
                    MSDLData {
                    MSDLHapticData {
                        HapticComposition(
                            listOf(
                                HapticCompositionPrimitive(
@@ -111,7 +111,7 @@ class MSDLRepositoryImpl : MSDLRepository {
                        )
                    },
                HapticToken.NEUTRAL_CONFIRMATION_HIGH_EMPHASIS to
                    MSDLData {
                    MSDLHapticData {
                        HapticComposition(
                            listOf(
                                HapticCompositionPrimitive(
@@ -123,7 +123,7 @@ class MSDLRepositoryImpl : MSDLRepository {
                        )
                    },
                HapticToken.LONG_PRESS to
                    MSDLData {
                    MSDLHapticData {
                        HapticComposition(
                            listOf(
                                HapticCompositionPrimitive(
@@ -135,7 +135,7 @@ class MSDLRepositoryImpl : MSDLRepository {
                        )
                    },
                HapticToken.SWIPE_THRESHOLD_INDICATOR to
                    MSDLData {
                    MSDLHapticData {
                        HapticComposition(
                            listOf(
                                HapticCompositionPrimitive(
@@ -147,7 +147,7 @@ class MSDLRepositoryImpl : MSDLRepository {
                        )
                    },
                HapticToken.TAP_HIGH_EMPHASIS to
                    MSDLData {
                    MSDLHapticData {
                        HapticComposition(
                            listOf(
                                HapticCompositionPrimitive(
@@ -159,7 +159,7 @@ class MSDLRepositoryImpl : MSDLRepository {
                        )
                    },
                HapticToken.TAP_MEDIUM_EMPHASIS to
                    MSDLData {
                    MSDLHapticData {
                        HapticComposition(
                            listOf(
                                HapticCompositionPrimitive(
@@ -171,7 +171,7 @@ class MSDLRepositoryImpl : MSDLRepository {
                        )
                    },
                HapticToken.DRAG_THRESHOLD_INDICATOR to
                    MSDLData {
                    MSDLHapticData {
                        HapticComposition(
                            listOf(
                                HapticCompositionPrimitive(
@@ -183,7 +183,7 @@ class MSDLRepositoryImpl : MSDLRepository {
                        )
                    },
                HapticToken.DRAG_INDICATOR to
                    MSDLData {
                    MSDLHapticData {
                        HapticComposition(
                            listOf(
                                HapticCompositionPrimitive(
@@ -195,7 +195,7 @@ class MSDLRepositoryImpl : MSDLRepository {
                        )
                    },
                HapticToken.TAP_LOW_EMPHASIS to
                    MSDLData {
                    MSDLHapticData {
                        HapticComposition(
                            listOf(
                                HapticCompositionPrimitive(
@@ -207,7 +207,7 @@ class MSDLRepositoryImpl : MSDLRepository {
                        )
                    },
                HapticToken.KEYPRESS_STANDARD to
                    MSDLData {
                    MSDLHapticData {
                        HapticComposition(
                            listOf(
                                HapticCompositionPrimitive(
@@ -219,7 +219,7 @@ class MSDLRepositoryImpl : MSDLRepository {
                        )
                    },
                HapticToken.KEYPRESS_SPACEBAR to
                    MSDLData {
                    MSDLHapticData {
                        HapticComposition(
                            listOf(
                                HapticCompositionPrimitive(
@@ -231,7 +231,7 @@ class MSDLRepositoryImpl : MSDLRepository {
                        )
                    },
                HapticToken.KEYPRESS_RETURN to
                    MSDLData {
                    MSDLHapticData {
                        HapticComposition(
                            listOf(
                                HapticCompositionPrimitive(
@@ -243,7 +243,7 @@ class MSDLRepositoryImpl : MSDLRepository {
                        )
                    },
                HapticToken.KEYPRESS_DELETE to
                    MSDLData {
                    MSDLHapticData {
                        HapticComposition(
                            listOf(
                                HapticCompositionPrimitive(
Loading