Skip to content

Add snippets for UI haptics docs on DAC #532

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.snippets.ui.haptics

import android.Manifest
import android.app.Activity
import android.os.Build
import android.os.VibrationEffect
import android.os.Vibrator
import androidx.annotation.RequiresApi
import androidx.annotation.RequiresPermission

@RequiresApi(api = Build.VERSION_CODES.S)
class CustomVibrationCompositions : Activity() {
var vibrator: Vibrator = getApplicationContext().getSystemService(Vibrator::class.java)

@RequiresPermission(Manifest.permission.VIBRATE)
// [START android_ui_haptics_composed_vibration_effect]
fun createComposedVibrationEffect() {
vibrator.vibrate(
VibrationEffect.startComposition()
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_SLOW_RISE)
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
.compose()
)
}
// [END android_ui_haptics_composed_vibration_effect]

@RequiresPermission(Manifest.permission.VIBRATE)
// [START android_ui_haptics_gap_between_primitives]
fun gapBetweenPrimitives() {
val delayMs: Int = 100
vibrator.vibrate(
VibrationEffect.startComposition()
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_SPIN, 0.8f)
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_SPIN, 0.6f)
.addPrimitive(
VibrationEffect.Composition.PRIMITIVE_THUD, 1.0f, delayMs
)
.compose()
)
}
// [END android_ui_haptics_gap_between_primitives]

@RequiresPermission(Manifest.permission.VIBRATE)
private fun checkPrimitivesSupport() {
// [START android_ui_haptics_check_single_primitive_support]
val primitive: Int = VibrationEffect.Composition.PRIMITIVE_LOW_TICK

if (vibrator.areAllPrimitivesSupported(primitive)) {
vibrator.vibrate(
VibrationEffect.startComposition()
.addPrimitive(primitive).compose()
)
} else {
// Play a predefined effect or custom pattern as a fallback.
}
// [END android_ui_haptics_check_single_primitive_support]

// [START android_ui_haptics_check_multiple_primitives_support]
val supported: BooleanArray = vibrator.arePrimitivesSupported(
VibrationEffect.Composition.PRIMITIVE_LOW_TICK,
VibrationEffect.Composition.PRIMITIVE_TICK,
VibrationEffect.Composition.PRIMITIVE_CLICK
)
// [END android_ui_haptics_check_multiple_primitives_support]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.example.snippets.ui.haptics;

import android.Manifest;
import android.app.Activity;
import android.os.Build;
import android.os.VibrationEffect;
import android.os.Vibrator;

import androidx.annotation.RequiresApi;
import androidx.annotation.RequiresPermission;

@RequiresApi(Build.VERSION_CODES.S)
public class CustomVibrationCompositionsJava extends Activity {
Vibrator vibrator = getApplicationContext().getSystemService(Vibrator.class);

@RequiresPermission(Manifest.permission.VIBRATE)
// [START android_ui_haptics_composed_vibration_effect]
private void createComposedVibrationEffect() {
vibrator.vibrate(
VibrationEffect.startComposition()
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_SLOW_RISE)
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
.compose());
}
// [END android_ui_haptics_composed_vibration_effect]

@RequiresPermission(Manifest.permission.VIBRATE)
// [START android_ui_haptics_gap_between_primitives]
private void gapBetweenPrimitives() {
int delayMs = 100;
vibrator.vibrate(
VibrationEffect.startComposition()
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_SPIN, 0.8f)
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_SPIN, 0.6f)
.addPrimitive(
VibrationEffect.Composition.PRIMITIVE_THUD, 1.0f, delayMs)
.compose());
}
// [END android_ui_haptics_gap_between_primitives]

@RequiresPermission(Manifest.permission.VIBRATE)
private void checkPrimitivesSupport() {
// [START android_ui_haptics_check_single_primitive_support]
int primitive = VibrationEffect.Composition.PRIMITIVE_LOW_TICK;

if (vibrator.areAllPrimitivesSupported(primitive)) {
vibrator.vibrate(VibrationEffect.startComposition()
.addPrimitive(primitive).compose());
} else {
// Play a predefined effect or custom pattern as a fallback.
}
// [END android_ui_haptics_check_single_primitive_support]

// [START android_ui_haptics_check_multiple_primitives_support]
boolean[] supported = vibrator.arePrimitivesSupported(
VibrationEffect.Composition.PRIMITIVE_LOW_TICK,
VibrationEffect.Composition.PRIMITIVE_TICK,
VibrationEffect.Composition.PRIMITIVE_CLICK);
// [END android_ui_haptics_check_multiple_primitives_support]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.snippets.ui.haptics

import android.Manifest
import android.app.Activity
import android.os.Build
import android.os.VibrationEffect
import android.os.Vibrator
import androidx.annotation.RequiresApi
import androidx.annotation.RequiresPermission

class CustomVibrationPatterns : Activity() {
@RequiresApi(Build.VERSION_CODES.M)
val vibrator = applicationContext.getSystemService(Vibrator::class.java) as Vibrator

// [START android_ui_haptics_ramp_up]
@RequiresPermission(Manifest.permission.VIBRATE)
@RequiresApi(Build.VERSION_CODES.O)
fun rampUpPattern(vibrator: Vibrator) {
val timings: LongArray = longArrayOf(
50, 50, 50, 50, 50, 100, 350, 25, 25, 25, 25, 200
)
val amplitudes: IntArray = intArrayOf(
33, 51, 75, 113, 170, 255, 0, 38, 62, 100, 160, 255
)
val repeatIndex = -1 // Don't repeat.

vibrator.vibrate(
VibrationEffect.createWaveform(
timings, amplitudes, repeatIndex
)
)
}
// [END android_ui_haptics_ramp_up]

@RequiresPermission(Manifest.permission.VIBRATE)
@RequiresApi(Build.VERSION_CODES.O)
// [START android_ui_haptics_repeat]
fun startRepeatVibration() {
val timings: LongArray = longArrayOf(50, 50, 100, 50, 50)
val amplitudes: IntArray = intArrayOf(64, 128, 255, 128, 64)
val repeat = 1 // Repeat from the second entry, index = 1.
val repeatingEffect = VibrationEffect.createWaveform(
timings, amplitudes, repeat
)
// repeatingEffect can be used in multiple places.

vibrator.vibrate(repeatingEffect)
}

// [START_EXCLUDE]
@RequiresPermission(Manifest.permission.VIBRATE)
@RequiresApi(Build.VERSION_CODES.M)
// [END_EXCLUDE]
fun stopRepeatVibrator() {
vibrator.cancel()
}
// [END android_ui_haptics_repeat]

@RequiresApi(api = Build.VERSION_CODES.O)
@RequiresPermission(Manifest.permission.VIBRATE)
// [START android_ui_haptics_fallback]
private fun patternWithFallback() {
val smoothTimings = longArrayOf(50, 50, 100, 50, 50)
val onOffTimings = longArrayOf(50, 100)
val amplitudes = intArrayOf(64, 128, 255, 128, 64)
val repeatIndex = -1 // Don't repeat.

if (vibrator.hasAmplitudeControl()) {
vibrator.vibrate(
VibrationEffect.createWaveform(
smoothTimings, amplitudes, repeatIndex
)
)
} else {
vibrator.vibrate(
VibrationEffect.createWaveform(
onOffTimings, repeatIndex
)
)
}
}
// [END android_ui_haptics_fallback]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.example.snippets.ui.haptics;

import android.Manifest;
import android.app.Activity;
import android.os.Build;
import android.os.VibrationEffect;
import android.os.Vibrator;

import androidx.annotation.RequiresApi;
import androidx.annotation.RequiresPermission;

@RequiresApi(api = Build.VERSION_CODES.M)
public class CustomVibrationPatternsJava extends Activity {
Vibrator vibrator = getApplicationContext().getSystemService(Vibrator.class);

// [START android_ui_haptics_ramp_up]
@RequiresApi(Build.VERSION_CODES.O)
@RequiresPermission(Manifest.permission.VIBRATE)
private void rampUpPattern(Vibrator vibrator) {
long[] timings = new long[] {
50, 50, 50, 50, 50, 100, 350, 25, 25, 25, 25, 200 };
int[] amplitudes = new int[] {
33, 51, 75, 113, 170, 255, 0, 38, 62, 100, 160, 255 };
int repeatIndex = -1; // Don't repeat.

vibrator.vibrate(VibrationEffect.createWaveform(
timings, amplitudes, repeatIndex));
}
// [END android_ui_haptics_ramp_up]

@RequiresApi(api = Build.VERSION_CODES.O)
@RequiresPermission(Manifest.permission.VIBRATE)
// [START android_ui_haptics_repeat]
private void startVibrating() {
long[] timings = new long[] { 50, 50, 100, 50, 50 };
int[] amplitudes = new int[] { 64, 128, 255, 128, 64 };
int repeat = 1; // Repeat from the second entry, index = 1.
VibrationEffect repeatingEffect = VibrationEffect.createWaveform(
timings, amplitudes, repeat);
// repeatingEffect can be used in multiple places.

vibrator.vibrate(repeatingEffect);
}

// [START_EXCLUDE]
@RequiresPermission(Manifest.permission.VIBRATE)
// [END_EXCLUDE]
private void stopVibrating() {
vibrator.cancel();
}
// [END android_ui_haptics_repeat]


// [START android_ui_haptics_fallback]
@RequiresApi(api = Build.VERSION_CODES.O)
@RequiresPermission(Manifest.permission.VIBRATE)
private void patternWithFallback() {
long[] smoothTimings = new long[] { 50, 50, 100, 50, 50 };
long[] onOffTimings = new long[] { 50, 100 };
int[] amplitudes = new int[] { 64, 128, 255, 128, 64 };
int repeatIndex = -1; // Don't repeat.

if (vibrator.hasAmplitudeControl()) {
vibrator.vibrate(VibrationEffect.createWaveform(
smoothTimings, amplitudes, repeatIndex));
} else {
vibrator.vibrate(VibrationEffect.createWaveform(
onOffTimings, repeatIndex));
}
}
// [END android_ui_haptics_fallback]
}