Loading msdllib/src/com/google/android/msdl/data/repository/MSDLRepository.kt +14 −8 Original line number Diff line number Diff line Loading @@ -15,23 +15,24 @@ */ package com.google.android.msdl.data.repository import androidx.annotation.VisibleForTesting import com.google.android.msdl.data.model.HapticToken import com.google.android.msdl.data.model.SoundToken /** * A repository of data for [ReferenceToken]. * A repository of data for [HapticToken] and [SoundToken]. * * The principle behind this repository is to hold the data for all tokens as a cache in memory. * This is only suitable if the number of tokens and the data stored is manageable. The purpose of * this design choice is to provide fast and easy access to the data when required to be played by * UI interactions. */ interface MSDLRepository { sealed interface MSDLRepository { /** * Get the [MSDLData] that corresponds to the given haptic reference token. This function needs * to be fast since it will be called repeatedly to deliver feedback. If necessary, a caching * strategy should be applied. * Get the [MSDLHapticData] that corresponds to the given haptic reference token. This function * needs to be fast since it will be called repeatedly to deliver feedback. If necessary, a * caching strategy should be applied. * * @param[hapticToken] The [HapticToken] that points to the data. * @return the data that corresponds to the token at the time this function is called. Loading @@ -39,14 +40,19 @@ interface MSDLRepository { fun getHapticData(hapticToken: HapticToken): MSDLHapticData? /** * Get the [MSDLData] that corresponds to the given sound reference token. This function needs * to be fast since it will be called repeatedly to deliver feedback. If necessary, a caching * strategy should be applied. * Get the [MSDLSoundData] that corresponds to the given sound reference token. This function * needs to be fast since it will be called repeatedly to deliver feedback. If necessary, a * caching strategy should be applied. * * @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): MSDLSoundData? companion object { @VisibleForTesting fun createRepository(): MSDLRepository = MSDLRepositoryImpl() } } /** Representation of data contained in a [MSDLRepository] */ Loading msdllib/src/com/google/android/msdl/data/repository/MSDLRepositoryImpl.kt +53 −53 Original line number Diff line number Diff line Loading @@ -23,7 +23,7 @@ import com.google.android.msdl.data.model.HapticToken import com.google.android.msdl.data.model.SoundToken /** A [MSDLRepository] that holds haptic compositions as haptic data. */ class MSDLRepositoryImpl : MSDLRepository { internal class MSDLRepositoryImpl : MSDLRepository { override fun getAudioData(soundToken: SoundToken): MSDLSoundData? { // TODO(b/345248875) Implement a caching strategy in accordance to the audio file strategy Loading Loading @@ -63,13 +63,13 @@ class MSDLRepositoryImpl : MSDLRepository { VibrationEffect.Composition.PRIMITIVE_SPIN, scale = 1f, delayMillis = SPIN_DELAY.toInt(), ) ), ), VibrationEffect.createWaveform( SPIN_WAVEFORM_TIMINGS, SPIN_WAVEFORM_AMPLITUDES, -1, ) ), ) }, HapticToken.NEGATIVE_CONFIRMATION_MEDIUM_EMPHASIS to Loading @@ -79,24 +79,24 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 0 delayMillis = 0, ), HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 114 delayMillis = 114, ), HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 114 ) delayMillis = 114, ), ), VibrationEffect.createWaveform( longArrayOf(10, 10, 10, 114, 10, 10, 10, 114, 10, 10, 10), intArrayOf(10, 255, 20, 0, 10, 255, 20, 0, 10, 255, 20), -1 ) -1, ), ) }, HapticToken.POSITIVE_CONFIRMATION_HIGH_EMPHASIS to Loading @@ -106,19 +106,19 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 0 delayMillis = 0, ), HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 114 ) delayMillis = 114, ), ), VibrationEffect.createWaveform( longArrayOf(10, 10, 10, 114, 10, 10, 10), intArrayOf(10, 255, 20, 0, 10, 255, 20), -1 ) -1, ), ) }, HapticToken.POSITIVE_CONFIRMATION_MEDIUM_EMPHASIS to Loading @@ -128,19 +128,19 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 0 delayMillis = 0, ), HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 52 ) delayMillis = 52, ), ), VibrationEffect.createWaveform( longArrayOf(10, 10, 10, 52, 10, 10, 10), intArrayOf(10, 255, 20, 0, 10, 255, 20), -1 ) -1, ), ) }, HapticToken.POSITIVE_CONFIRMATION_LOW_EMPHASIS to Loading @@ -150,19 +150,19 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_TICK, scale = 1f, delayMillis = 0 delayMillis = 0, ), HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 52 ) delayMillis = 52, ), ), VibrationEffect.createWaveform( longArrayOf(5, 52, 10, 10, 10), intArrayOf(100, 0, 10, 255, 20), -1 ) -1, ), ) }, HapticToken.NEUTRAL_CONFIRMATION_HIGH_EMPHASIS to Loading @@ -172,14 +172,14 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_THUD, scale = 1f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createWaveform( longArrayOf(50, 100, 100, 50), intArrayOf(5, 50, 20, 10), -1 ) -1, ), ) }, HapticToken.NEUTRAL_CONFIRMATION_MEDIUM_EMPHASIS to Loading @@ -192,7 +192,7 @@ class MSDLRepositoryImpl : MSDLRepository { delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ) }, HapticToken.LONG_PRESS to Loading @@ -202,10 +202,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ) }, HapticToken.SWIPE_THRESHOLD_INDICATOR to Loading @@ -215,10 +215,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 0.7f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ) }, HapticToken.TAP_HIGH_EMPHASIS to Loading @@ -228,10 +228,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 0.7f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ) }, HapticToken.TAP_MEDIUM_EMPHASIS to Loading @@ -241,10 +241,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 0.5f, delayMillis = 0 ), delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ) }, HapticToken.DRAG_THRESHOLD_INDICATOR to Loading @@ -254,10 +254,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_TICK, scale = 1f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK), ) }, HapticToken.DRAG_INDICATOR to Loading @@ -267,10 +267,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_TICK, scale = 0.5f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK), ) }, HapticToken.TAP_LOW_EMPHASIS to Loading @@ -280,10 +280,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 0.3f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ) }, HapticToken.KEYPRESS_STANDARD to Loading @@ -293,10 +293,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_TICK, scale = 0.7f, delayMillis = 0 ), delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK), ) }, HapticToken.KEYPRESS_SPACEBAR to Loading @@ -306,10 +306,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 0.7f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ) }, HapticToken.KEYPRESS_RETURN to Loading @@ -319,10 +319,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 0.7f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ) }, HapticToken.KEYPRESS_DELETE to Loading @@ -332,12 +332,12 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ) } }, ) } } msdllib/src/com/google/android/msdl/domain/MSDLPlayer.kt +28 −19 Original line number Diff line number Diff line Loading @@ -16,11 +16,11 @@ package com.google.android.msdl.domain import android.content.Context import android.os.VibratorManager import android.os.Vibrator import com.google.android.msdl.data.model.FeedbackLevel import com.google.android.msdl.data.model.HapticComposition import com.google.android.msdl.data.model.MSDLToken import com.google.android.msdl.data.repository.MSDLRepository import com.google.android.msdl.data.repository.MSDLRepositoryImpl import com.google.android.msdl.domain.MSDLPlayerImpl.Companion.REQUIRED_PRIMITIVES import java.util.concurrent.Executor Loading Loading @@ -59,34 +59,43 @@ interface MSDLPlayer { /** * Create a new [MSDLPlayer]. * * @param[context] The [Context] this player will get its services from. * @param[vibrator] The [Vibrator] this player will use for haptic playback. * @param[executor] An [Executor] to schedule haptic playback. * @param[useHapticFeedbackForToken] A map that determines if a haptic fallback effect * should be used to play haptics for a given [MSDLToken]. If null, the map will be * created using the support information from the given vibrator. */ fun createPlayer( context: Context, vibrator: Vibrator, executor: Executor = Executors.newSingleThreadExecutor(), useHapticFeedbackForToken: Map<MSDLToken, Boolean>? = null, ): MSDLPlayer { // Gather vibration dependencies val vibratorManager = context.getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager val vibrator = vibratorManager.defaultVibrator // Create repository val repository = MSDLRepositoryImpl() // Determine the support for haptic primitives to know if fallbacks will be used // Determine the support for haptic primitives to know if fallbacks will be used. // This can be provided by the client. If omitted, it will be determined from the // supported primitives of the given vibrator. val shouldUseFallbackForToken = useHapticFeedbackForToken ?: createHapticFallbackDecisionMap(vibrator, repository) return MSDLPlayerImpl(repository, vibrator, executor, shouldUseFallbackForToken) } private fun createHapticFallbackDecisionMap( vibrator: Vibrator, repository: MSDLRepository, ): Map<MSDLToken, Boolean> { val supportedPrimitives = REQUIRED_PRIMITIVES.associateWith { vibrator.arePrimitivesSupported(it).first() } val useHapticFallbackForToken = MSDLToken.entries.associateWith { token -> // For each token, determine if the haptic data from the repository should use // the fallback effect return MSDLToken.entries.associateWith { token -> // For each token, determine if the haptic data from the repository // should use the fallback effect. val hapticComposition = repository.getHapticData(token.hapticToken)?.get() as? HapticComposition hapticComposition?.shouldPlayFallback(supportedPrimitives) hapticComposition?.shouldPlayFallback(supportedPrimitives) ?: false } return MSDLPlayerImpl(repository, vibrator, executor, useHapticFallbackForToken) } } } Loading msdllib/src/com/google/android/msdl/domain/MSDLPlayerImpl.kt +2 −5 Original line number Diff line number Diff line Loading @@ -36,7 +36,7 @@ import java.util.concurrent.Executor * @param[useHapticFallbackForToken] A map that determines if the haptic fallback effect should be * used for a given token. */ class MSDLPlayerImpl( internal class MSDLPlayerImpl( private val repository: MSDLRepository, private val vibrator: Vibrator, private val executor: Executor, Loading @@ -55,10 +55,7 @@ class MSDLPlayerImpl( playData(token, properties) } private fun playData( token: MSDLToken, properties: InteractionProperties?, ) { private fun playData(token: MSDLToken, properties: InteractionProperties?) { // Gather the data from the repositories val hapticData = repository.getHapticData(token.hapticToken) val soundData = repository.getAudioData(token.soundToken) Loading msdllib/tests/src/com/google/android/msdl/data/repository/MSDLRepositoryImplTest.kt +1 −7 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ package com.google.android.msdl.data.repository import com.google.android.msdl.data.model.HapticComposition import com.google.android.msdl.data.model.HapticToken import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 Loading @@ -27,12 +26,7 @@ import org.junit.runners.JUnit4 @RunWith(JUnit4::class) class MSDLRepositoryImplTest { private lateinit var repository: MSDLRepositoryImpl @Before fun setup() { repository = MSDLRepositoryImpl() } private val repository = MSDLRepository.createRepository() @Test fun getHapticData_forAllHapticTokens_returnsCompositions() { Loading Loading
msdllib/src/com/google/android/msdl/data/repository/MSDLRepository.kt +14 −8 Original line number Diff line number Diff line Loading @@ -15,23 +15,24 @@ */ package com.google.android.msdl.data.repository import androidx.annotation.VisibleForTesting import com.google.android.msdl.data.model.HapticToken import com.google.android.msdl.data.model.SoundToken /** * A repository of data for [ReferenceToken]. * A repository of data for [HapticToken] and [SoundToken]. * * The principle behind this repository is to hold the data for all tokens as a cache in memory. * This is only suitable if the number of tokens and the data stored is manageable. The purpose of * this design choice is to provide fast and easy access to the data when required to be played by * UI interactions. */ interface MSDLRepository { sealed interface MSDLRepository { /** * Get the [MSDLData] that corresponds to the given haptic reference token. This function needs * to be fast since it will be called repeatedly to deliver feedback. If necessary, a caching * strategy should be applied. * Get the [MSDLHapticData] that corresponds to the given haptic reference token. This function * needs to be fast since it will be called repeatedly to deliver feedback. If necessary, a * caching strategy should be applied. * * @param[hapticToken] The [HapticToken] that points to the data. * @return the data that corresponds to the token at the time this function is called. Loading @@ -39,14 +40,19 @@ interface MSDLRepository { fun getHapticData(hapticToken: HapticToken): MSDLHapticData? /** * Get the [MSDLData] that corresponds to the given sound reference token. This function needs * to be fast since it will be called repeatedly to deliver feedback. If necessary, a caching * strategy should be applied. * Get the [MSDLSoundData] that corresponds to the given sound reference token. This function * needs to be fast since it will be called repeatedly to deliver feedback. If necessary, a * caching strategy should be applied. * * @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): MSDLSoundData? companion object { @VisibleForTesting fun createRepository(): MSDLRepository = MSDLRepositoryImpl() } } /** Representation of data contained in a [MSDLRepository] */ Loading
msdllib/src/com/google/android/msdl/data/repository/MSDLRepositoryImpl.kt +53 −53 Original line number Diff line number Diff line Loading @@ -23,7 +23,7 @@ import com.google.android.msdl.data.model.HapticToken import com.google.android.msdl.data.model.SoundToken /** A [MSDLRepository] that holds haptic compositions as haptic data. */ class MSDLRepositoryImpl : MSDLRepository { internal class MSDLRepositoryImpl : MSDLRepository { override fun getAudioData(soundToken: SoundToken): MSDLSoundData? { // TODO(b/345248875) Implement a caching strategy in accordance to the audio file strategy Loading Loading @@ -63,13 +63,13 @@ class MSDLRepositoryImpl : MSDLRepository { VibrationEffect.Composition.PRIMITIVE_SPIN, scale = 1f, delayMillis = SPIN_DELAY.toInt(), ) ), ), VibrationEffect.createWaveform( SPIN_WAVEFORM_TIMINGS, SPIN_WAVEFORM_AMPLITUDES, -1, ) ), ) }, HapticToken.NEGATIVE_CONFIRMATION_MEDIUM_EMPHASIS to Loading @@ -79,24 +79,24 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 0 delayMillis = 0, ), HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 114 delayMillis = 114, ), HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 114 ) delayMillis = 114, ), ), VibrationEffect.createWaveform( longArrayOf(10, 10, 10, 114, 10, 10, 10, 114, 10, 10, 10), intArrayOf(10, 255, 20, 0, 10, 255, 20, 0, 10, 255, 20), -1 ) -1, ), ) }, HapticToken.POSITIVE_CONFIRMATION_HIGH_EMPHASIS to Loading @@ -106,19 +106,19 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 0 delayMillis = 0, ), HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 114 ) delayMillis = 114, ), ), VibrationEffect.createWaveform( longArrayOf(10, 10, 10, 114, 10, 10, 10), intArrayOf(10, 255, 20, 0, 10, 255, 20), -1 ) -1, ), ) }, HapticToken.POSITIVE_CONFIRMATION_MEDIUM_EMPHASIS to Loading @@ -128,19 +128,19 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 0 delayMillis = 0, ), HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 52 ) delayMillis = 52, ), ), VibrationEffect.createWaveform( longArrayOf(10, 10, 10, 52, 10, 10, 10), intArrayOf(10, 255, 20, 0, 10, 255, 20), -1 ) -1, ), ) }, HapticToken.POSITIVE_CONFIRMATION_LOW_EMPHASIS to Loading @@ -150,19 +150,19 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_TICK, scale = 1f, delayMillis = 0 delayMillis = 0, ), HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 52 ) delayMillis = 52, ), ), VibrationEffect.createWaveform( longArrayOf(5, 52, 10, 10, 10), intArrayOf(100, 0, 10, 255, 20), -1 ) -1, ), ) }, HapticToken.NEUTRAL_CONFIRMATION_HIGH_EMPHASIS to Loading @@ -172,14 +172,14 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_THUD, scale = 1f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createWaveform( longArrayOf(50, 100, 100, 50), intArrayOf(5, 50, 20, 10), -1 ) -1, ), ) }, HapticToken.NEUTRAL_CONFIRMATION_MEDIUM_EMPHASIS to Loading @@ -192,7 +192,7 @@ class MSDLRepositoryImpl : MSDLRepository { delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ) }, HapticToken.LONG_PRESS to Loading @@ -202,10 +202,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ) }, HapticToken.SWIPE_THRESHOLD_INDICATOR to Loading @@ -215,10 +215,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 0.7f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ) }, HapticToken.TAP_HIGH_EMPHASIS to Loading @@ -228,10 +228,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 0.7f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ) }, HapticToken.TAP_MEDIUM_EMPHASIS to Loading @@ -241,10 +241,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 0.5f, delayMillis = 0 ), delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ) }, HapticToken.DRAG_THRESHOLD_INDICATOR to Loading @@ -254,10 +254,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_TICK, scale = 1f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK), ) }, HapticToken.DRAG_INDICATOR to Loading @@ -267,10 +267,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_TICK, scale = 0.5f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK), ) }, HapticToken.TAP_LOW_EMPHASIS to Loading @@ -280,10 +280,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 0.3f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ) }, HapticToken.KEYPRESS_STANDARD to Loading @@ -293,10 +293,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_TICK, scale = 0.7f, delayMillis = 0 ), delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK), ) }, HapticToken.KEYPRESS_SPACEBAR to Loading @@ -306,10 +306,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 0.7f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ) }, HapticToken.KEYPRESS_RETURN to Loading @@ -319,10 +319,10 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 0.7f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ) }, HapticToken.KEYPRESS_DELETE to Loading @@ -332,12 +332,12 @@ class MSDLRepositoryImpl : MSDLRepository { HapticCompositionPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, scale = 1f, delayMillis = 0 delayMillis = 0, ) ), VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ) } }, ) } }
msdllib/src/com/google/android/msdl/domain/MSDLPlayer.kt +28 −19 Original line number Diff line number Diff line Loading @@ -16,11 +16,11 @@ package com.google.android.msdl.domain import android.content.Context import android.os.VibratorManager import android.os.Vibrator import com.google.android.msdl.data.model.FeedbackLevel import com.google.android.msdl.data.model.HapticComposition import com.google.android.msdl.data.model.MSDLToken import com.google.android.msdl.data.repository.MSDLRepository import com.google.android.msdl.data.repository.MSDLRepositoryImpl import com.google.android.msdl.domain.MSDLPlayerImpl.Companion.REQUIRED_PRIMITIVES import java.util.concurrent.Executor Loading Loading @@ -59,34 +59,43 @@ interface MSDLPlayer { /** * Create a new [MSDLPlayer]. * * @param[context] The [Context] this player will get its services from. * @param[vibrator] The [Vibrator] this player will use for haptic playback. * @param[executor] An [Executor] to schedule haptic playback. * @param[useHapticFeedbackForToken] A map that determines if a haptic fallback effect * should be used to play haptics for a given [MSDLToken]. If null, the map will be * created using the support information from the given vibrator. */ fun createPlayer( context: Context, vibrator: Vibrator, executor: Executor = Executors.newSingleThreadExecutor(), useHapticFeedbackForToken: Map<MSDLToken, Boolean>? = null, ): MSDLPlayer { // Gather vibration dependencies val vibratorManager = context.getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager val vibrator = vibratorManager.defaultVibrator // Create repository val repository = MSDLRepositoryImpl() // Determine the support for haptic primitives to know if fallbacks will be used // Determine the support for haptic primitives to know if fallbacks will be used. // This can be provided by the client. If omitted, it will be determined from the // supported primitives of the given vibrator. val shouldUseFallbackForToken = useHapticFeedbackForToken ?: createHapticFallbackDecisionMap(vibrator, repository) return MSDLPlayerImpl(repository, vibrator, executor, shouldUseFallbackForToken) } private fun createHapticFallbackDecisionMap( vibrator: Vibrator, repository: MSDLRepository, ): Map<MSDLToken, Boolean> { val supportedPrimitives = REQUIRED_PRIMITIVES.associateWith { vibrator.arePrimitivesSupported(it).first() } val useHapticFallbackForToken = MSDLToken.entries.associateWith { token -> // For each token, determine if the haptic data from the repository should use // the fallback effect return MSDLToken.entries.associateWith { token -> // For each token, determine if the haptic data from the repository // should use the fallback effect. val hapticComposition = repository.getHapticData(token.hapticToken)?.get() as? HapticComposition hapticComposition?.shouldPlayFallback(supportedPrimitives) hapticComposition?.shouldPlayFallback(supportedPrimitives) ?: false } return MSDLPlayerImpl(repository, vibrator, executor, useHapticFallbackForToken) } } } Loading
msdllib/src/com/google/android/msdl/domain/MSDLPlayerImpl.kt +2 −5 Original line number Diff line number Diff line Loading @@ -36,7 +36,7 @@ import java.util.concurrent.Executor * @param[useHapticFallbackForToken] A map that determines if the haptic fallback effect should be * used for a given token. */ class MSDLPlayerImpl( internal class MSDLPlayerImpl( private val repository: MSDLRepository, private val vibrator: Vibrator, private val executor: Executor, Loading @@ -55,10 +55,7 @@ class MSDLPlayerImpl( playData(token, properties) } private fun playData( token: MSDLToken, properties: InteractionProperties?, ) { private fun playData(token: MSDLToken, properties: InteractionProperties?) { // Gather the data from the repositories val hapticData = repository.getHapticData(token.hapticToken) val soundData = repository.getAudioData(token.soundToken) Loading
msdllib/tests/src/com/google/android/msdl/data/repository/MSDLRepositoryImplTest.kt +1 −7 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ package com.google.android.msdl.data.repository import com.google.android.msdl.data.model.HapticComposition import com.google.android.msdl.data.model.HapticToken import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 Loading @@ -27,12 +26,7 @@ import org.junit.runners.JUnit4 @RunWith(JUnit4::class) class MSDLRepositoryImplTest { private lateinit var repository: MSDLRepositoryImpl @Before fun setup() { repository = MSDLRepositoryImpl() } private val repository = MSDLRepository.createRepository() @Test fun getHapticData_forAllHapticTokens_returnsCompositions() { Loading