1 /* 2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.compose.ui.platform 18 19 import android.content.Context 20 import android.os.Build 21 import android.os.VibrationEffect 22 import android.os.Vibrator 23 import android.view.HapticFeedbackConstants 24 import android.view.View 25 import androidx.compose.ui.hapticfeedback.HapticFeedback 26 import androidx.compose.ui.hapticfeedback.HapticFeedbackType 27 28 /** 29 * Provide a default implementation of HapticFeedback to call through to the view's 30 * [performHapticFeedback] with the associated HapticFeedbackConstant. 31 * 32 * @param view The current view, used for forwarding haptic feedback requests. 33 */ 34 internal class DefaultHapticFeedback(private val view: View) : HapticFeedback { performHapticFeedbacknull35 override fun performHapticFeedback(hapticFeedbackType: HapticFeedbackType) { 36 when (hapticFeedbackType) { 37 HapticFeedbackType.Confirm -> 38 view.performHapticFeedback(HapticFeedbackConstants.CONFIRM) 39 HapticFeedbackType.ContextClick -> 40 view.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK) 41 HapticFeedbackType.GestureEnd -> 42 view.performHapticFeedback(HapticFeedbackConstants.GESTURE_END) 43 HapticFeedbackType.GestureThresholdActivate -> 44 view.performHapticFeedback(HapticFeedbackConstants.GESTURE_THRESHOLD_ACTIVATE) 45 HapticFeedbackType.KeyboardTap -> 46 view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP) 47 HapticFeedbackType.LongPress -> 48 view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) 49 HapticFeedbackType.Reject -> view.performHapticFeedback(HapticFeedbackConstants.REJECT) 50 HapticFeedbackType.SegmentFrequentTick -> 51 view.performHapticFeedback(HapticFeedbackConstants.SEGMENT_FREQUENT_TICK) 52 HapticFeedbackType.SegmentTick -> 53 view.performHapticFeedback(HapticFeedbackConstants.SEGMENT_TICK) 54 HapticFeedbackType.TextHandleMove -> 55 view.performHapticFeedback(HapticFeedbackConstants.TEXT_HANDLE_MOVE) 56 HapticFeedbackType.ToggleOff -> 57 view.performHapticFeedback(HapticFeedbackConstants.TOGGLE_OFF) 58 HapticFeedbackType.ToggleOn -> 59 view.performHapticFeedback(HapticFeedbackConstants.TOGGLE_ON) 60 HapticFeedbackType.VirtualKey -> 61 view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY) 62 } 63 } 64 } 65 66 /** Provide a no-op implementation of HapticFeedback */ 67 internal class NoHapticFeedback : HapticFeedback { performHapticFeedbacknull68 override fun performHapticFeedback(hapticFeedbackType: HapticFeedbackType) { 69 // No-op 70 } 71 } 72 73 /** Contains defaults for haptics functionality */ 74 internal object HapticDefaults { 75 /** 76 * Returns whether the device supports premium haptic feedback. 77 * 78 * @param context The current context for access to the Vibrator via System Service. 79 */ isPremiumVibratorEnablednull80 fun isPremiumVibratorEnabled(context: Context): Boolean { 81 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { 82 val vibrator = context.getSystemService(Vibrator::class.java) 83 84 // NB whilst the 'areAllPrimitivesSupported' API needs R (API 30), we need S (API 85 // 31) so that PRIMITIVE_THUD is available. 86 if ( 87 vibrator.areAllPrimitivesSupported( 88 VibrationEffect.Composition.PRIMITIVE_CLICK, 89 VibrationEffect.Composition.PRIMITIVE_TICK, 90 VibrationEffect.Composition.PRIMITIVE_THUD 91 ) 92 ) { 93 return true 94 } 95 } 96 97 return false 98 } 99 } 100