Vibration.vibrate(pattern?, repeat?) drives the motor: 400 ms with no argument on Android. On Android a pattern alternates waiting and vibrating, starting with a wait; iOS vibrates for a fixed time (about 400 ms) and treats the numbers as pauses. repeat: true loops until Vibration.cancel(). Android needs the VIBRATE permission, which expo-haptics already added to BookNest.
// Android pattern: wait, buzz, wait, buzz ... in milliseconds
const ORDER_PLACED = [0, 80, 60, 80];
// ...inside Buzz, each entry becomes a button:
['Vibration.vibrate()', () => Vibration.vibrate()], // 400 ms on Android
['Pattern', () => Vibration.vibrate(ORDER_PLACED)],
['Repeat, then cancel', () => {
Vibration.vibrate([0, 200, 300], true); // loop from index 0
setTimeout(() => Vibration.cancel(), 1200);
}],
['Haptics: Confirm', () => Haptics.performAndroidHapticsAsync(
Haptics.AndroidHaptics.Confirm)],
['Haptics: impact Medium', () => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium)],The emulator has no motor, but Android's vibrator service logs every request. After the five buttons were pressed in order, BookNest's entries read:
adb shell dumpsys vibrator_manager | grep com.anonymous.booknest \
| awk -F'|' '{print $3 "|" $4 "|" $12}' \
| sed -E 's/ +/ /g; s/\(amplitude=([0-9.]+)\)/@\1/g; s/(duration|played): //g'finished | 286ms | [Step=0ms@0.00,Step=80ms@1.00,Step=60ms@0.00,Step=80ms@1.00] cancelled_by_user | 1223ms | [Step=0ms@0.00,Step=200ms@1.00,Step=300ms@0.00], repeat=0 finished | 665ms | Step=400ms@1.00 finished | 187ms | Prebaked=CLICK(MEDIUM, with fallback) finished | 111ms | [Step=0ms@0.00,Step=43ms@0.20]
Each line shows the status, total time and steps played. Entries are grouped by usage, so the plain 400 ms buzz comes third; the busy emulator stretched its total. The pattern played exactly as written, and the repeating one ran until cancel() at 1.2 s. The last two lines belong to Haptics Beyond Vibration.