Skip to content

Android SDK

The Pulsar Android SDK provides haptic feedback through three building blocks: Presets, PatternComposer, and RealtimeComposer. All are accessed through the main Pulsar class.

  • Android API 24+ (Android 7.0)
  • Kotlin 1.9+

Latest available version: 1.1.2

Add Pulsar as a Gradle dependency:

dependencies {
implementation("com.swmansion:pulsar:1.1.2")
}

Declare the vibration permission in your app’s AndroidManifest.xml:

<manifest ...>
<uses-permission android:name="android.permission.VIBRATE" />
<application ...>
...
</application>
</manifest>

Without android.permission.VIBRATE, Android will block vibration playback. Pulsar logs a warning and skips the vibration instead of crashing.

Create a Pulsar instance with an Android Context:

import com.swmansion.pulsar.Pulsar
val pulsar = Pulsar(context)

A collection of ready-to-use haptic patterns accessed through pulsar.getPresets().

val presets = pulsar.getPresets()
MethodDescription
afterglow()A three-beat phrase that dissolves gently, ideal for soft endings or gradually quieting feedback.
aftershock()A firm opening that settles calmly, ideal for transitions needing a strong start and a gentle finish.
alarm()Relentless and urgent, best for critical errors or emergencies that require immediate attention.
anvil()The full weight of a massive collision, conveys sheer physical force and momentum.
applause()A growing wave of appreciation, ideal for celebratory moments or social approval.

Example

val presets = pulsar.getPresets()
presets.applause()

These mirror standard haptic feedback styles shared across platforms.

MethodDescription
systemImpactHeavy()Heavy impact
systemImpactLight()Light impact
systemImpactMedium()Medium impact
systemImpactRigid()Rigid impact
systemImpactSoft()Soft impact

Example

val presets = pulsar.getPresets()
presets.systemImpactMedium()

Android exposes additional system effects beyond the cross-platform set.

MethodDescription
systemCalendarDate()HapticFeedbackConstants.CALENDAR_DATE
systemClockTick()HapticFeedbackConstants.CLOCK_TICK
systemConfirm()HapticFeedbackConstants.CONFIRM
systemContextClick()HapticFeedbackConstants.CONTEXT_CLICK
systemDragCrossing()HapticFeedbackConstants.DRAG_CROSSING

Example

val presets = pulsar.getPresets()
presets.systemPrimitiveClick()

You can play any preset by its string name using getByName(). This returns a Preset? that you call play() on.

Available names:

  • Afterglow
  • Aftershock
  • Alarm
  • Anvil
  • Applause
  • Ascent
  • BalloonPop
  • Barrage

Example

val presets = pulsar.getPresets()
// Direct call
presets.dogBark()
// By name
presets.getByName("SystemImpactMedium")?.play()

Composes and plays custom haptic patterns. Get a new instance from pulsar.getPatternComposer(). Each call returns a fresh composer, so you can manage multiple patterns independently.

val composer = pulsar.getPatternComposer()

Parses a PatternData object and prepares it for playback.

fun parsePattern(hapticsData: PatternData)

Plays the previously parsed pattern.

fun play()

Stops all playback.

fun stop()
val composer = pulsar.getPatternComposer()
val pattern = PatternData(
continuousPattern = ContinuousPattern(
amplitude = listOf(
ValuePoint(time = 0, value = 0f),
ValuePoint(time = 200, value = 1f),
ValuePoint(time = 400, value = 0f),
),
frequency = listOf(
ValuePoint(time = 0, value = 0.3f),
ValuePoint(time = 400, value = 0.8f),
)
),
discretePattern = listOf(
ConfigPoint(time = 0, amplitude = 1f, frequency = 0.5f),
ConfigPoint(time = 100, amplitude = 0.5f, frequency = 0.5f),
)
)
composer.parsePattern(pattern)
composer.play()

Provides real-time haptic control with live amplitude and frequency modulation. Useful for gesture-driven or continuously evolving haptic experiences. Get the shared instance from pulsar.getRealtimeComposer().

val realtime = pulsar.getRealtimeComposer()

An optional strategy parameter controls how continuous haptics are simulated:

val realtime = pulsar.getRealtimeComposer(strategy = RealtimeComposerStrategy.ENVELOPE)
StrategyDescription
ENVELOPEEnvelope API approximation (API 36+)
PRIMITIVE_TICKComposition API with varying tick intervals
PRIMITIVE_COMPLEXMultiple primitives selected based on frequency
ENVELOPE_WITH_DISCRETE_PRIMITIVESDefault. Envelope API for continuous events (API 36+); composition primitives for discrete events (API 33+).

Starts the realtime composer so that subsequent set(amplitude, frequency) calls play. set(...) requires start() first — calls made before start() or after stop() are silent no-ops. After stop(), call start() again before the next set(...). Available on RealtimeComposer and every strategy implementation (envelope, primitive, etc.).

fun start()

Updates the ongoing haptic with new amplitude and frequency values. Values should be in the 0-1 range. Has no effect until start() has been called; becomes a no-op again after stop(). Pass startIfNeeded = true to auto-start the composer when it is not already active — defaults to false, preserving the no-op-when-inactive behavior.

fun set(amplitude: Float, frequency: Float, startIfNeeded: Boolean = false)

Plays a single discrete haptic event.

fun playDiscrete(amplitude: Float, frequency: Float)

Stops the active continuous haptic.

fun stop()

Returns true if a continuous haptic is currently playing.

fun isActive(): Boolean
val realtime = pulsar.getRealtimeComposer()
// Begin a continuous haptic — required before set(...) will play
realtime.start()
// Update parameters over time as the gesture progresses
realtime.set(amplitude = 0.5f, frequency = 0.8f)
realtime.set(amplitude = 1.0f, frequency = 0.3f)
// Play a one-off discrete event
realtime.playDiscrete(amplitude = 0.7f, frequency = 0.5f)
// End the continuous haptic. After this the composer is inactive
// again — call start() before the next set(...).
realtime.stop()

Note: set(amplitude, frequency) requires start() first. Calls before start() or after stop() are silent no-ops. Pair start() with the beginning of a gesture and stop() with its end, or pass startIfNeeded = true to set(...) to opt into auto-start when no clear begin hook is available.


Configuration methods available directly on the Pulsar instance.

MethodDescription
enableHaptics(state: Boolean)Enable or disable all haptic feedback
enableSound(state: Boolean)Enable or disable audio simulation
enableCache(state: Boolean)Enable or disable preset caching
clearCache()Clear the preset cache
preloadPresets(presetNames: List<String>)Preload presets by name for faster playback
stopHaptics()Stop all currently playing haptics
hapticSupport()Returns the device’s CompatibilityMode
forceHapticsSupportLevel(mode: CompatibilityMode)Override the detected support level
enableImpulseCompositionMode(state: Boolean)Enable or disable VibrationEffect.Composition for impulse-only presets (enabled by default)
val pulsar = Pulsar(context)
// Preload frequently used presets
pulsar.preloadPresets(listOf("Earthquake", "Success"))
// Disable haptics temporarily
pulsar.enableHaptics(false)
// Check device support
val support = pulsar.hapticSupport()
if (support >= CompatibilityMode.STANDARD_SUPPORT) {
pulsar.getPresets().success()
}

Describes a complete haptic pattern with discrete pulses and continuous envelope curves.

data class PatternData(
val continuousPattern: ContinuousPattern,
val discretePattern: List<ConfigPoint>
)

Represents continuous haptic curves for amplitude and frequency.

data class ContinuousPattern(
val amplitude: List<ValuePoint>,
val frequency: List<ValuePoint>
)

A single point in a continuous curve.

data class ValuePoint(
val time: Long, // Milliseconds from pattern start
val value: Float // Normalized value (0-1)
)

A single discrete haptic event.

data class ConfigPoint(
val time: Long, // Milliseconds from pattern start
val amplitude: Float, // Intensity (0-1)
val frequency: Float // Sharpness (0-1)
)

Use discretePattern for distinct taps and impacts. Use continuousPattern envelopes to shape a sustained haptic over time.

The haptic capability level of the current device, returned by pulsar.hapticSupport(). The SDK gracefully degrades based on what the device supports.

enum class CompatibilityMode {
NO_SUPPORT, // No haptic support
LIMITED_SUPPORT, // Timing-based waveform vibration (API 26+)
STANDARD_SUPPORT, // Amplitude + timing control
ADVANCED_SUPPORT, // Envelope + frequency profile (API 36+)
}

Controls how continuous haptics are rendered on the device.

enum class RealtimeComposerStrategy {
ENVELOPE, // Envelope API approximation (API 36+)
PRIMITIVE_TICK, // Composition API with varying intervals
PRIMITIVE_COMPLEX, // Multiple primitives based on frequency
ENVELOPE_WITH_DISCRETE_PRIMITIVES, // Envelope for continuous; primitives for discrete
}

The interface that all preset implementations conform to.

interface Preset {
fun play()
}