PeachHaptics.kt

3.0 KB · raw

1package com.peachpasswords.haptics23import android.content.Context4import android.os.Build5import android.os.VibrationEffect6import android.os.Vibrator7import android.os.VibratorManager8import android.view.HapticFeedbackConstants9import android.view.View1011object PeachHaptics {12    fun onUnlock(view: View) = view.performHapticFeedback(sinceR(HapticFeedbackConstants.CONFIRM, HapticFeedbackConstants.VIRTUAL_KEY))13    fun onEntryTap(view: View) = view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)14    fun onCopy(view: View) = view.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK)15    fun onSheetOpen(view: View) = view.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)16    fun onSheetClose(view: View) = view.performHapticFeedback(sinceR(HapticFeedbackConstants.GESTURE_END, HapticFeedbackConstants.CONTEXT_CLICK))17    fun onError(view: View) = view.performHapticFeedback(sinceR(HapticFeedbackConstants.REJECT, HapticFeedbackConstants.LONG_PRESS))18    fun onButton(view: View) = view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)19    fun onCardFocus(view: View) = view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)2021    /**22     * CONFIRM / REJECT / GESTURE_END only exist from API 30. The constants are23     * `int`s inlined at compile time, so on API 26-29 they don't fail loudly —24     * `performHapticFeedback` just returns false and the device stays silent.25     * Each falls back to the nearest pre-30 effect with the same intent: a short26     * tick for confirm, a heavier buzz for reject, a soft click to close.27     */28    private fun sinceR(api30: Int, fallback: Int): Int =29        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) api30 else fallback3031    fun onLongPress(context: Context) = vibrate(context, 20L, 180)32    fun onSwipeCopy(context: Context) = vibrate(context, 15L, 150)3334    fun onPairingComplete(context: Context) {35        val vibrator = getVibrator(context) ?: return36        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {37            vibrator.vibrate(38                VibrationEffect.createWaveform(39                    longArrayOf(0, 30, 60, 50),40                    intArrayOf(0, 180, 0, 120),41                    -1,42                )43            )44        }45    }4647    private fun vibrate(context: Context, duration: Long, amplitude: Int) {48        val vibrator = getVibrator(context) ?: return49        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {50            vibrator.vibrate(VibrationEffect.createOneShot(duration, amplitude))51        } else {52            @Suppress("DEPRECATION")53            vibrator.vibrate(duration)54        }55    }5657    private fun getVibrator(context: Context): Vibrator? {58        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {59            val manager = context.getSystemService(VibratorManager::class.java)60            manager?.defaultVibrator61        } else {62            @Suppress("DEPRECATION")63            context.getSystemService(Context.VIBRATOR_SERVICE) as? Vibrator64        }65    }66}