diff --git a/Examples/UIExplorer/js/VibrationExample.js b/Examples/UIExplorer/js/VibrationExample.js
index 554ae2f1f5514d..00e8cbd97bc4e0 100644
--- a/Examples/UIExplorer/js/VibrationExample.js
+++ b/Examples/UIExplorer/js/VibrationExample.js
@@ -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 (
+
+ {patternDescription}
+
+ );
+ },
+ },
{
title: 'Vibration.vibrate()',
render() {
@@ -51,12 +84,12 @@ exports.examples = [
},
},
{
- title: 'Vibration.vibrate([0, 500, 200, 500])',
+ title: `Vibration.vibrate(${patternLiteral})`,
render() {
return (
Vibration.vibrate([0, 500, 200, 500])}>
+ onPress={() => Vibration.vibrate(pattern)}>
Vibrate once
@@ -65,12 +98,12 @@ exports.examples = [
},
},
{
- title: 'Vibration.vibrate([0, 500, 200, 500], true)',
+ title: `Vibration.vibrate(${patternLiteral}, true)`,
render() {
return (
Vibration.vibrate([0, 500, 200, 500], true)}>
+ onPress={() => Vibration.vibrate(pattern, true)}>
Vibrate until cancel
diff --git a/Libraries/Vibration/Vibration.js b/Libraries/Vibration/Vibration.js
index a60f75453928d3..e3d9e5a3959217 100644
--- a/Libraries/Vibration/Vibration.js
+++ b/Libraries/Vibration/Vibration.js
@@ -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 `` 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, 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, 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 = 400, repeat: boolean = false) {
if (Platform.OS === 'android') {
@@ -37,10 +84,13 @@ 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');
}
@@ -48,12 +98,10 @@ var Vibration = {
},
/**
* Stop vibration
- *
- * @platform android
*/
cancel: function() {
if (Platform.OS === 'ios') {
- console.warn('Vibration.cancel is not supported on iOS');
+ _vibrating = false;
} else {
RCTVibration.cancel();
}