Android
Vibration Patterns
Algorithm Development
Mobile App Development
Intensity Control

Algorithm for generating vibration patterns ranging in intensity in Android?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

On Android, “vibration intensity” is not purely an algorithm problem. Whether you can control strength directly depends on the Android version and the device hardware. The practical solution is to generate waveform patterns and, where supported, assign amplitude values explicitly.

What Android Actually Lets You Control

On modern Android, the Vibrator API supports VibrationEffect, and waveform vibration can take an amplitude array alongside the timing array. That gives you a way to express a pattern that ramps up, peaks, and fades out.

The important limitation is hardware support. Some devices support amplitude control, and some do not. If amplitude control is missing, you can still vary the feel of the pattern with different pulse lengths and pauses, but not with true strength changes.

You can check this at runtime:

kotlin
1import android.content.Context
2import android.os.Build
3import android.os.VibrationEffect
4import android.os.Vibrator
5
6fun playRisingPattern(context: Context) {
7    val vibrator = context.getSystemService(Vibrator::class.java)
8
9    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
10        val timings = longArrayOf(0, 80, 40, 120, 40, 180, 40, 240)
11        val amplitudes = intArrayOf(
12            0,
13            64, 0,
14            128, 0,
15            192, 0,
16            255
17        )
18
19        val effect = VibrationEffect.createWaveform(timings, amplitudes, -1)
20        vibrator.vibrate(effect)
21    }
22}

In this pattern, the motor starts with a weak pulse and grows stronger over time. The -1 repeat index means the waveform plays once.

Designing a Simple Intensity Algorithm

If the goal is “generate patterns ranging in intensity,” a useful model is:

  • choose a fixed number of pulses
  • scale pulse duration as intensity rises
  • if amplitude control exists, scale amplitude too
  • insert short gaps so individual pulses are still perceivable

For example, map an intensity value from 1 to 10 into both pulse duration and amplitude:

kotlin
1import android.content.Context
2import android.os.Build
3import android.os.VibrationEffect
4import android.os.Vibrator
5import kotlin.math.roundToInt
6
7fun vibrateWithIntensity(context: Context, intensity: Int) {
8    val vibrator = context.getSystemService(Vibrator::class.java)
9    val level = intensity.coerceIn(1, 10)
10
11    val pulse = 40L + level * 15L
12    val gap = (70L - level * 4L).coerceAtLeast(20L)
13
14    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
15        val amplitude = (level / 10.0 * 255).roundToInt().coerceIn(1, 255)
16        val effect = VibrationEffect.createWaveform(
17            longArrayOf(0, pulse, gap, pulse, gap, pulse),
18            intArrayOf(0, amplitude, 0, amplitude, 0, amplitude),
19            -1
20        )
21        vibrator.vibrate(effect)
22    } else {
23        @Suppress("DEPRECATION")
24        vibrator.vibrate(longArrayOf(0, pulse, gap, pulse, gap, pulse), -1)
25    }
26}

This is not physically perfect, because haptic motors are not linear. But it is a solid application-level algorithm: the user gets a more forceful pattern as the intensity value rises, and older devices still get a usable fallback.

Fallback Strategy for Devices Without Amplitude Control

If hasAmplitudeControl() is false, the motor strength usually cannot be changed directly. In that situation, approximate stronger feedback by changing the structure of the pattern:

  • longer pulses feel stronger
  • shorter gaps feel more urgent
  • repeated pulses feel more intense than one isolated pulse

That means your algorithm should really have two modes:

  • amplitude-aware mode for newer capable devices
  • duration-and-rhythm mode for everyone else

This separation matters because otherwise you may think your amplitude logic is working while the hardware is silently ignoring it.

Practical UX Guidance

Haptics should communicate state, not just produce noise. Intensity patterns make sense for:

  • urgency levels in alerts
  • confirmation versus warning feedback
  • game events with escalating impact
  • accessibility signals where tactile strength carries meaning

Try to keep the vocabulary small. For many apps, three or four levels are easier to understand and tune than a continuous ten-step scale.

It is also worth testing on real hardware. Emulator behavior is irrelevant here, and different vendors ship different vibration motors and driver behavior.

Common Pitfalls

The biggest mistake is assuming Android guarantees amplitude control. It does not. Your code may run, but the device can ignore the amplitude array.

Another issue is trying to encode too many subtle levels. Mobile haptics are coarse compared with audio volume or screen brightness, so tiny differences are often lost.

Developers also sometimes forget the VIBRATE permission in the manifest or rely only on emulator tests. Both lead to misleading conclusions during development.

Finally, avoid excessively long or aggressive patterns. A technically correct waveform can still be a poor user experience if it feels annoying or intrusive.

Summary

  • Use VibrationEffect.createWaveform for patterned vibration on modern Android.
  • True intensity control depends on device support for amplitude control.
  • Build a fallback algorithm based on pulse length and gap timing for unsupported hardware.
  • Map application intensity levels into simple, tested haptic patterns.
  • Validate on real devices because motor behavior varies across manufacturers.

Course illustration
Course illustration

All Rights Reserved.