Skip to content
Closed
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
41 changes: 37 additions & 4 deletions Examples/UIExplorer/js/VibrationExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,45 @@ var {
Text,
TouchableHighlight,
Vibration,
Platform,
} = ReactNative;

exports.framework = 'React';
exports.title = 'Vibration';
exports.description = 'Vibration API';

var pattern, patternLiteral, patternDescription;
if (Platform.OS === 'android') {
pattern = [0, 500, 200, 500];
patternLiteral = '[0, 500, 200, 500]';
patternDescription = `${patternLiteral}
arg 0: duration to wait before turning the vibrator on.
arg with odd: vibration length.
arg with even: duration to wait before next vibration.
`;
} else {
pattern = [0, 1000, 2000, 3000];
patternLiteral = '[0, 1000, 2000, 3000]';
patternDescription = `${patternLiteral}
vibration length on iOS is fixed.
pattern controls durations BETWEEN each vibration only.

arg 0: duration to wait before turning the vibrator on.
subsequent args: duration to wait before next vibrattion.
`;
}

exports.examples = [
{
title: 'Pattern Descriptions',
render() {
return (
<View style={styles.wrapper}>
<Text>{patternDescription}</Text>
</View>
);
},
},
{
title: 'Vibration.vibrate()',
render() {
Expand All @@ -51,12 +84,12 @@ exports.examples = [
},
},
{
title: 'Vibration.vibrate([0, 500, 200, 500])',
title: `Vibration.vibrate(${patternLiteral})`,
render() {
return (
<TouchableHighlight
style={styles.wrapper}
onPress={() => Vibration.vibrate([0, 500, 200, 500])}>
onPress={() => Vibration.vibrate(pattern)}>
<View style={styles.button}>
<Text>Vibrate once</Text>
</View>
Expand All @@ -65,12 +98,12 @@ exports.examples = [
},
},
{
title: 'Vibration.vibrate([0, 500, 200, 500], true)',
title: `Vibration.vibrate(${patternLiteral}, true)`,
render() {
return (
<TouchableHighlight
style={styles.wrapper}
onPress={() => Vibration.vibrate([0, 500, 200, 500], true)}>
onPress={() => Vibration.vibrate(pattern, true)}>
<View style={styles.button}>
<Text>Vibrate until cancel</Text>
</View>
Expand Down
60 changes: 54 additions & 6 deletions Libraries/Vibration/Vibration.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,59 @@ var Platform = require('Platform');
*
* There will be no effect on devices that do not support Vibration, eg. the simulator.
*
* Note for android
* **Note for android**
* add `<uses-permission android:name="android.permission.VIBRATE"/>` to `AndroidManifest.xml`
*
* Vibration patterns are currently unsupported.
* **Android Usage:**
*
* [0, 500, 200, 500]
* V(0.5s) --wait(0.2s)--> V(0.5s)
*
* [300, 500, 200, 500]
* --wait(0.3s)--> V(0.5s) --wait(0.2s)--> V(0.5s)
*
* **iOS Usage:**
* if first argument is 0, it will not be included in pattern array.
*
* [0, 1000, 2000, 3000]
* V(fixed) --wait(1s)--> V(fixed) --wait(2s)--> V(fixed) --wait(3s)--> V(fixed)
*/

var _vibrating: boolean = false;
var _id: number = 0; // _id is necessary to prevent race condition.

function vibrateByPattern(pattern: Array<number>, repeat: boolean = false) {
if (_vibrating) {
return;
}
_vibrating = true;
if (pattern[0] === 0) {
RCTVibration.vibrate();
pattern = pattern.slice(1);
}
if (pattern.length === 0) {
_vibrating = false;
return;
}
setTimeout(() => vibrateScheduler(++_id, pattern, repeat, 1), pattern[0]);
}

function vibrateScheduler(id, pattern: Array<number>, repeat: boolean, nextIndex: number) {
if (!_vibrating || id !== _id) {
return;
}
RCTVibration.vibrate();
if (nextIndex >= pattern.length) {
if (repeat) {
nextIndex = 0;
} else {
_vibrating = false;
return;
}
}
setTimeout(() => vibrateScheduler(id, pattern, repeat, nextIndex+1), pattern[nextIndex]);
}

var Vibration = {
vibrate: function(pattern: number | Array<number> = 400, repeat: boolean = false) {
if (Platform.OS === 'android') {
Expand All @@ -37,23 +84,24 @@ var Vibration = {
throw new Error('Vibration pattern should be a number or array');
}
} else {
if (_vibrating) {
return;
}
if (typeof pattern === 'number') {
RCTVibration.vibrate();
} else if (Array.isArray(pattern)) {
console.warn('Vibration patterns are not supported on iOS');
vibrateByPattern(pattern, repeat);
} else {
throw new Error('Vibration pattern should be a number or array');
}
}
},
/**
* Stop vibration
*
* @platform android
*/
cancel: function() {
if (Platform.OS === 'ios') {
console.warn('Vibration.cancel is not supported on iOS');
_vibrating = false;
} else {
RCTVibration.cancel();
}
Expand Down