How to Use Vibration Effects in Android Apps (Using Jetpack Compose)

Effective Haptics

Michihiro Iwasaki
6 min readMay 21, 2024

Android devices support a range of vibration effects, from long-duration vibrations for call notifications to short bursts for click feedback. In this article, I’ll show you how to implement these vibration effects using Jetpack Compose.

📳 Principles of Using Vibration Effects

Before delving into the implementation of vibration effects, it’s crucial to understand the principles guiding their use to avoid providing a poor user experience. Consider, for instance, an app that vibrates every time the screen changes — such frequent vibrations could become annoying and are generally not recommended.

When considering vibration effects in your app, think about the following scenarios:

  1. Highlighting Critical Notifications:
    Vibration effects can be effectively used for important notifications, such as incoming calls, where making the user aware immediately is crucial.
  2. Confirming Important Interactions:
    For actions that involve changing critical settings or features within an app, using a vibration effect can help confirm to the user that their tap was registered. This is especially useful for buttons or switches where immediate feedback is necessary.

While these are common scenarios for employing vibration effects, always assess whether they are genuinely needed for your specific use case.

Additionally, I recommend reviewing the official Android Developers page on haptics design principles provided by Google for more insights:

🔧 Ready for Using VibrationEffect

To implement vibration effects in an Android app, we will use the VibrationEffect class. This class requires user permission and is supported on devices running Android API level 26 or higher. However, for this tutorial, we'll target devices with API level 29 or above to utilize some of the newer APIs.

1.. Set the necessary permission in the AndroidManifest.xml:

<!-- Add the vibration permission to your manifest file -->
<uses-permission android:name="android.permission.VIBRATE"/>

2.. Update the minimum SDK version in your module’s build.gradle.kts file:

// build.gradle.kts
android {
defaultConfig {
applicationId = "com.example.myapp"
minSdkVersion(29) // Ensure this is set to API level 29 or higher
// Other settings
}
}

After updating these configurations, make sure to click the ‘Sync Now’ button in your IDE to apply changes and verify that the sync completes successfully.

🖥️ Building the UI

For this example, we will use buttons to demonstrate different vibration effects. We’ll place five buttons centered on the screen. Since the focus of this tutorial is not on UI design, feel free to adjust the design and layout of these buttons as you see fit. Below is a sample code illustrating how to set up the buttons:

// VibrationEx.kt
@Composable
fun VibrationEx() {
Column(
modifier = Modifier
.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
OutlinedButton(
onClick = { /*TODO: Add Vibration Logic Here*/ }
) {
Text(text = "Vibration")
}

// Toggle button for activating a feature
var isActive by remember {
mutableStateOf(false)
}
FilledIconToggleButton(
checked = isActive,
onCheckedChange = {
isActive = !isActive
// TODO: Add Repeating Vibration
},
modifier = Modifier.padding(top = 32.dp)
) {
Icon(
imageVector = Icons.Default.Notifications,
contentDescription = "Toggle Notification"
)
}

// Buttons for different vibration effects
Button(
onClick = { /*TODO: Add Click Effect Logic*/ },
modifier = Modifier.padding(top = 64.dp)
) {
Text(text = "Click Effect")
}
Button(
onClick = { /*TODO: Add Heavy Click Effect Logic*/ },
modifier = Modifier.padding(vertical = 32.dp)
) {
Text(text = "Heavy Click Effect")
}
Button(
onClick = { /*TODO: Add Double Click Effect Logic*/ }
) {
Text(text = "Double Click Effect")
}
}
}

This setup provides a simple interface for testing different vibration patterns. Each button is linked to a specific type of vibration effect, which we will implement in the upcoming steps.

① Simple Vibration (No Repeat)

In this step, we’ll integrate a simple vibration effect into the ‘OutlinedButton’ Composable at the top of the example screen.

Setup Context and Vibrator Instance:

First, obtain the Context and an instance of the Vibrator class within your Composable:

// VibrationEx.kt
val context = LocalContext.current
val vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator

Implementing the Vibration Effect:

Next, implement a simple vibration effect using the createOneShot() method of the VibrationEffect class. This method requires two parameters: the duration of the vibration in milliseconds and the strength of the vibration as an integer. Use VibrationEffect.DEFAULT_AMPLITUDE for the default vibration strength.

Here’s how to configure a vibration of 500 milliseconds with default strength:

OutlinedButton(
onClick = {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vibrator.vibrate(
VibrationEffect.createOneShot(
500L,
VibrationEffect.DEFAULT_AMPLITUDE
)
)
}
}
) {
Text(text = "Vibration")
}

Test the Vibration:

To demonstrate the vibration effect, you can view the video below where I’ve placed the device on a desk to amplify the vibration sound. Make sure your device’s sound is on to hear the effect.

Next Steps:

In the upcoming section, we will explore how to implement repeating vibration effects.

② Repeating Vibration

If you want to vibrate a device repeatedly, use the createWaveform() method. This method takes two primary arguments:

  1. A LongArray specifying the timing of the vibration cycle. Setting the first element of the array to 0 means the vibration starts immediately.
  2. An integer indicating the start point of the repeating cycle. If you don’t want the vibration to repeat, set this value to -1.

The example code below uses longArrayOf(0, 500, 300), meaning the vibration starts immediately, continues for 500ms, then stops for 300ms. This cycle (500ms of vibration followed by 300ms of rest) repeats starting from the second element of the array.

FilledIconToggleButton(
checked = isActive,
onCheckedChange = {
isActive = !isActive
if (isActive) {
vibrator.vibrate(
VibrationEffect.createWaveform(
longArrayOf(0, 500, 300), // timings
1 // start repeating from index 1
)
)
} else {
vibrator.cancel()
}
}
) {
Icon(
imageVector = Icons.Default.Notifications,
contentDescription = "Toggle Notification"
)
}

The video below demonstrates the repeating vibration. Remember, if you set a repeating vibration, it’s important to also provide a method to stop it, such as invoking the cancel() method on the vibrator instance.

In the next section, we’ll explore how to implement click effects in our example app.

③ Click Effects

Android devices offer built-in vibration effects for interactions such as button clicks. Using click effects, we can provide tactile feedback to users, enhancing the user experience. These effects can be easily implemented in an app using the createPredefined() method.

Note: The createPredefined() method requires API level 29 or higher.

This method takes an Int as an argument, which you should pass as a predefined constant. For instance, to implement a simple click effect, you can use VibrationEffect.EFFECT_CLICK:

Button(
onClick = {
vibrator.vibrate(
VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)
)
}
) {
Text(text = "Click Effect")
}

For a stronger click effect, use VibrationEffect.EFFECT_HEAVY_CLICK:

Button(
onClick = {
vibrator.vibrate(
VibrationEffect.createPredefined(VibrationEffect.EFFECT_HEAVY_CLICK)
)
}
) {
Text(text = "Heavy Click Effect")
}

Additionally, for a double click effect, use VibrationEffect.EFFECT_DOUBLE_CLICK:

Button(
onClick = {
vibrator.vibrate(
VibrationEffect.createPredefined(VibrationEffect.EFFECT_DOUBLE_CLICK)
)
}
) {
Text(text = "Double Click Effect")
}

You can observe these click effects in the video below. Note that the vibration sounds may be subtle due to their low volume.

The code snippets provided in this article are available on GitHub, allowing you to download and experiment with them directly. Here is the link:

<aside>
<p>
Thank you for reading!<br>
If you enjoyed this post, <br>
I'd appreciate a clap. 😄
</p>
</aside>

--

--