From 9007d66637d4b89677d66ef6ba07e786de469bfa Mon Sep 17 00:00:00 2001 From: Mike Monteith Date: Tue, 5 Apr 2016 17:47:49 +0100 Subject: [PATCH] Android click sound onPress of Touchable component Android's onClick listener will trigger a sound effect by default when a user has system sounds enabled. Since React implements it's own click model, we should manually trigger the sound. To test: 1. Ensure volume is turned up 2. Settings > Sound & Notification > Other sounds > enable Touch sounds 3. Click any Touchable* React component 4. You should hear a click on press 5. Settings > Sound & Notification > Other sounds > disable Touch sounds 6. Click any Touchable* React component 7. You should not hear a click --- Libraries/Components/Touchable/Touchable.js | 14 ++++++++++++++ .../react/views/view/ReactViewManager.java | 11 ++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Libraries/Components/Touchable/Touchable.js b/Libraries/Components/Touchable/Touchable.js index 9bae52a0333cb6..d7d546ec2f4122 100644 --- a/Libraries/Components/Touchable/Touchable.js +++ b/Libraries/Components/Touchable/Touchable.js @@ -14,8 +14,11 @@ const BoundingDimensions = require('BoundingDimensions'); const Position = require('Position'); const React = require('React'); // eslint-disable-line no-unused-vars +const ReactNative = require('ReactNative'); const TouchEventUtils = require('fbjs/lib/TouchEventUtils'); const View = require('View'); +const UIManager = require('UIManager'); +const Platform = require('Platform'); const keyMirror = require('fbjs/lib/keyMirror'); const normalizeColor = require('normalizeColor'); @@ -712,12 +715,23 @@ var TouchableMixin = { var shouldInvokePress = !IsLongPressingIn[curState] || pressIsLongButStillCallOnPress; if (shouldInvokePress && this.touchableHandlePress) { + if (Platform.OS === 'android') { + this._playClickSound(); + } this.touchableHandlePress(e); } } this.touchableDelayTimeout && clearTimeout(this.touchableDelayTimeout); this.touchableDelayTimeout = null; + }, + + _playClickSound: function() { + UIManager.dispatchViewManagerCommand( + ReactNative.findNodeHandle(this), + UIManager.RCTView.Commands.playClickSound, + null + ); } }; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java index 6a4bd5d264914b..e8f85a22b7decf 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java @@ -16,6 +16,7 @@ import android.graphics.Rect; import android.os.Build; +import android.view.SoundEffectConstants; import android.view.View; import com.facebook.csslayout.CSSConstants; @@ -46,6 +47,7 @@ public class ReactViewManager extends ViewGroupManager { }; private static final int CMD_HOTSPOT_UPDATE = 1; private static final int CMD_SET_PRESSED = 2; + private static final int CMD_PLAY_CLICK_SOUND = 3; @ReactProp(name = "accessible") public void setAccessible(ReactViewGroup view, boolean accessible) { @@ -158,7 +160,10 @@ public ReactViewGroup createViewInstance(ThemedReactContext context) { @Override public Map getCommandsMap() { - return MapBuilder.of("hotspotUpdate", CMD_HOTSPOT_UPDATE, "setPressed", CMD_SET_PRESSED); + return MapBuilder.of( + "hotspotUpdate", CMD_HOTSPOT_UPDATE, + "setPressed", CMD_SET_PRESSED, + "playClickSound", CMD_PLAY_CLICK_SOUND); } @Override @@ -184,6 +189,10 @@ public void receiveCommand(ReactViewGroup root, int commandId, @Nullable Readabl root.setPressed(args.getBoolean(0)); break; } + case CMD_PLAY_CLICK_SOUND: { + root.playSoundEffect(SoundEffectConstants.CLICK); + break; + } } }