diff --git a/interface/resources/controllers/touchscreenvirtualpad.json b/interface/resources/controllers/touchscreenvirtualpad.json
index bae1172152..e98fb7ff2f 100644
--- a/interface/resources/controllers/touchscreenvirtualpad.json
+++ b/interface/resources/controllers/touchscreenvirtualpad.json
@@ -23,7 +23,9 @@
                 "invert"
             ],
             "to": "Actions.Pitch"
-        }
+        },
+
+        { "from": "TouchscreenVirtualPad.RB", "to": "Standard.RB"}
 
     ]
 }
diff --git a/interface/resources/images/handshake.png b/interface/resources/images/handshake.png
new file mode 100644
index 0000000000..ae4252e9e5
Binary files /dev/null and b/interface/resources/images/handshake.png differ
diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp
index a1809f3438..d710e9d8ff 100644
--- a/libraries/animation/src/AnimInverseKinematics.cpp
+++ b/libraries/animation/src/AnimInverseKinematics.cpp
@@ -865,10 +865,6 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar
 
 //virtual
 const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut, const AnimPoseVec& underPoses) {
-#ifdef Q_OS_ANDROID
-    // disable IK on android
-    return underPoses;
-#endif
 
     // allows solutionSource to be overridden by an animVar
     auto solutionSource = animVars.lookup(_solutionSourceVar, (int)_solutionSource);
diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp
index d8b8cbd54a..9828a8beda 100644
--- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp
@@ -74,30 +74,15 @@ void Basic2DWindowOpenGLDisplayPlugin::customizeContext() {
         }
     }
 
-
-    _virtualPadJumpBtnPixelSize = dpi * VirtualPad::Manager::JUMP_BTN_FULL_PIXELS / VirtualPad::Manager::DPI;
-    if (!_virtualPadJumpBtnTexture) {
-        auto iconPath = PathUtils::resourcesPath() + "images/fly.png";
-        auto image = QImage(iconPath);
-        if (image.format() != QImage::Format_ARGB32) {
-            image = image.convertToFormat(QImage::Format_ARGB32);
-        }
-        if ((image.width() > 0) && (image.height() > 0)) {
-            image = image.scaled(_virtualPadJumpBtnPixelSize, _virtualPadJumpBtnPixelSize, Qt::KeepAspectRatio);
-            image = image.mirrored();
-
-            _virtualPadJumpBtnTexture = gpu::Texture::createStrict(
-                    gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
-                    image.width(), image.height(),
-                    gpu::Texture::MAX_NUM_MIPS,
-                    gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
-            _virtualPadJumpBtnTexture->setSource("virtualPad jump");
-            auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
-            _virtualPadJumpBtnTexture->setUsage(usage.build());
-            _virtualPadJumpBtnTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
-            _virtualPadJumpBtnTexture->assignStoredMip(0, image.byteCount(), image.constBits());
-            _virtualPadJumpBtnTexture->setAutoGenerateMips(true);
-        }
+    if (_virtualPadButtons.size() == 0) {
+        _virtualPadButtons.append(VirtualPadButton(
+                dpi * VirtualPad::Manager::BTN_FULL_PIXELS / VirtualPad::Manager::DPI,
+                PathUtils::resourcesPath() + "images/fly.png",
+                VirtualPad::Manager::Button::JUMP));
+        _virtualPadButtons.append(VirtualPadButton(
+                dpi * VirtualPad::Manager::BTN_FULL_PIXELS / VirtualPad::Manager::DPI,
+                PathUtils::resourcesPath() + "images/handshake.png",
+                VirtualPad::Manager::Button::HANDSHAKE));
     }
 #endif
     Parent::customizeContext();
@@ -133,8 +118,6 @@ void Basic2DWindowOpenGLDisplayPlugin::compositeExtra() {
                                                                                                     _virtualPadPixelSize, _virtualPadPixelSize);
         auto stickTransform = DependencyManager::get<CompositorHelper>()->getPoint2DTransform(virtualPadManager.getLeftVirtualPad()->getCurrentTouch(),
                                                                                               _virtualPadPixelSize, _virtualPadPixelSize);
-        auto jumpTransform = DependencyManager::get<CompositorHelper>()->getPoint2DTransform(virtualPadManager.getJumpButtonPosition(),
-                                                                                             _virtualPadJumpBtnPixelSize, _virtualPadJumpBtnPixelSize);
 
         render([&](gpu::Batch& batch) {
             batch.enableStereo(false);
@@ -151,9 +134,9 @@ void Basic2DWindowOpenGLDisplayPlugin::compositeExtra() {
             batch.setModelTransform(stickTransform);
             batch.draw(gpu::TRIANGLE_STRIP, 4);
 
-            batch.setResourceTexture(0, _virtualPadJumpBtnTexture);
-            batch.setModelTransform(jumpTransform);
-            batch.draw(gpu::TRIANGLE_STRIP, 4);
+            foreach(VirtualPadButton virtualPadButton, _virtualPadButtons) {
+                virtualPadButton.draw(batch, virtualPadManager.getButtonPosition(virtualPadButton._button));
+            }
         });
     }
 #endif
@@ -178,3 +161,47 @@ bool Basic2DWindowOpenGLDisplayPlugin::isThrottled() const {
 QScreen* Basic2DWindowOpenGLDisplayPlugin::getFullscreenTarget() {
     return qApp->primaryScreen();
 }
+
+#if defined(Q_OS_ANDROID)
+
+Basic2DWindowOpenGLDisplayPlugin::VirtualPadButton::VirtualPadButton(qreal pixelSize,
+                                                                     QString iconPath,
+                                                                     VirtualPad::Manager::Button button) :
+    _pixelSize { pixelSize },
+    _button { button }
+{
+    if (!_texture) {
+        auto image = QImage(iconPath);
+        if (image.format() != QImage::Format_ARGB32) {
+            image = image.convertToFormat(QImage::Format_ARGB32);
+        }
+        if ((image.width() > 0) && (image.height() > 0)) {
+            image = image.scaled(_pixelSize, _pixelSize, Qt::KeepAspectRatio);
+            image = image.mirrored();
+
+            _texture = gpu::Texture::createStrict(
+                    gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
+                    image.width(), image.height(),
+                    gpu::Texture::MAX_NUM_MIPS,
+                    gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
+            _texture->setSource(iconPath.toStdString());
+            auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
+            _texture->setUsage(usage.build());
+            _texture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
+            _texture->assignStoredMip(0, image.byteCount(), image.constBits());
+            _texture->setAutoGenerateMips(true);
+        }
+    }
+}
+
+void Basic2DWindowOpenGLDisplayPlugin::VirtualPadButton::draw(gpu::Batch &batch,
+                                                              glm::vec2 buttonPosition) {
+    auto transform = DependencyManager::get<CompositorHelper>()->getPoint2DTransform(
+            buttonPosition,
+            _pixelSize, _pixelSize);
+    batch.setResourceTexture(0, _texture);
+    batch.setModelTransform(transform);
+    batch.draw(gpu::TRIANGLE_STRIP, 4);
+}
+
+#endif
\ No newline at end of file
diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h
index 944d5e89d1..cc304c19c2 100644
--- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h
+++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h
@@ -9,6 +9,10 @@
 
 #include "OpenGLDisplayPlugin.h"
 
+#if defined(Q_OS_ANDROID)
+#include "VirtualPadManager.h"
+#endif
+
 const float TARGET_FRAMERATE_Basic2DWindowOpenGL = 60.0f;
 
 class QScreen;
@@ -51,5 +55,23 @@ private:
 
     gpu::TexturePointer _virtualPadJumpBtnTexture;
     qreal _virtualPadJumpBtnPixelSize;
+
+    gpu::TexturePointer _virtualPadRbBtnTexture;
+    qreal _virtualPadRbBtnPixelSize;
+
+    class VirtualPadButton {
+    public:
+
+        VirtualPadButton() {}
+        VirtualPadButton(qreal pixelSize, QString iconPath, VirtualPad::Manager::Button button);
+
+        void draw(gpu::Batch& batch, glm::vec2 buttonPosition);
+
+        gpu::TexturePointer _texture;
+        qreal _pixelSize;
+        VirtualPad::Manager::Button _button;
+    };
+    QVector<VirtualPadButton> _virtualPadButtons;
+
 #endif
 };
diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp
index 247f484c95..6bb743bad0 100644
--- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp
+++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp
@@ -66,7 +66,7 @@ void TouchscreenVirtualPadDevice::resize() {
         _fixedRadius = _screenDPI * 0.5f * VirtualPad::Manager::BASE_DIAMETER_PIXELS / VirtualPad::Manager::DPI;
         _fixedRadiusForCalc = _fixedRadius - _screenDPI * VirtualPad::Manager::STICK_RADIUS_PIXELS / VirtualPad::Manager::DPI;
 
-        _jumpButtonRadius = _screenDPI * VirtualPad::Manager::JUMP_BTN_TRIMMED_RADIUS_PIXELS / VirtualPad::Manager::DPI;
+        _buttonRadius = _screenDPI * VirtualPad::Manager::BTN_TRIMMED_RADIUS_PIXELS / VirtualPad::Manager::DPI;
     }
 
     auto& virtualPadManager = VirtualPad::Manager::instance();
@@ -86,11 +86,21 @@ void TouchscreenVirtualPadDevice::setupControlsPositions(VirtualPad::Manager& vi
     virtualPadManager.getLeftVirtualPad()->setFirstTouch(_moveRefTouchPoint);
 
     // Jump button
-    float jumpBtnPixelSize = _screenDPI * VirtualPad::Manager::JUMP_BTN_FULL_PIXELS / VirtualPad::Manager::DPI;
-    float rightMargin = _screenDPI * VirtualPad::Manager::JUMP_BTN_RIGHT_MARGIN_PIXELS / VirtualPad::Manager::DPI;
-    float bottomMargin = _screenDPI * VirtualPad::Manager::JUMP_BTN_BOTTOM_MARGIN_PIXELS/ VirtualPad::Manager::DPI;
-    _jumpButtonPosition = glm::vec2( eventScreen->availableSize().width() - rightMargin - jumpBtnPixelSize, eventScreen->availableSize().height() - bottomMargin - _jumpButtonRadius - _extraBottomMargin);
-    virtualPadManager.setJumpButtonPosition(_jumpButtonPosition);
+    float btnPixelSize = _screenDPI * VirtualPad::Manager::BTN_FULL_PIXELS / VirtualPad::Manager::DPI;
+    float rightMargin = _screenDPI * VirtualPad::Manager::BTN_RIGHT_MARGIN_PIXELS / VirtualPad::Manager::DPI;
+    float bottomMargin = _screenDPI * VirtualPad::Manager::BTN_BOTTOM_MARGIN_PIXELS/ VirtualPad::Manager::DPI;
+    glm::vec2 jumpButtonPosition = glm::vec2( eventScreen->availableSize().width() - rightMargin - btnPixelSize, eventScreen->availableSize().height() - bottomMargin - _buttonRadius - _extraBottomMargin);
+    glm::vec2 rbButtonPosition = glm::vec2( eventScreen->availableSize().width() - rightMargin - btnPixelSize, eventScreen->availableSize().height() - 2 * bottomMargin - 3 * _buttonRadius - _extraBottomMargin);
+
+    // Avoid generating buttons in portrait mode
+    if ( eventScreen->availableSize().width() > eventScreen->availableSize().height() && _buttonsManager.buttonsCount() == 0) {
+        _buttonsManager.addButton(TouchscreenButton(JUMP, JUMP_BUTTON, _buttonRadius, jumpButtonPosition, _inputDevice ));
+        _buttonsManager.addButton(TouchscreenButton(RB, RB_BUTTON, _buttonRadius, rbButtonPosition, _inputDevice ));
+
+        virtualPadManager.setButtonPosition(VirtualPad::Manager::Button::JUMP, jumpButtonPosition);
+        virtualPadManager.setButtonPosition(VirtualPad::Manager::Button::HANDSHAKE, rbButtonPosition);
+    }
+
 }
 
 float clip(float n, float lower, float upper) {
@@ -237,7 +247,7 @@ void TouchscreenVirtualPadDevice::touchEndEvent(const QTouchEvent* event) {
     if (!virtualPadManager.isEnabled() && !virtualPadManager.isHidden()) {
         moveTouchEnd();
         viewTouchEnd();
-        jumpTouchEnd();
+        _buttonsManager.endTouchForAll();
         return;
     }
     // touch end here is a big reset -> resets both pads
@@ -246,7 +256,7 @@ void TouchscreenVirtualPadDevice::touchEndEvent(const QTouchEvent* event) {
     debugPoints(event, " END ----------------");
     moveTouchEnd();
     viewTouchEnd();
-    jumpTouchEnd();
+    _buttonsManager.endTouchForAll();
     _inputDevice->_axisStateMap.clear();
     _inputDevice->_buttonPressedMap.clear();
 }
@@ -282,11 +292,11 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) {
     const QList<QTouchEvent::TouchPoint>& tPoints = event->touchPoints();
     bool moveTouchFound = false;
     bool viewTouchFound = false;
-    bool jumpTouchFound = false;
 
     int idxMoveStartingPointCandidate = -1;
     int idxViewStartingPointCandidate = -1;
-    int idxJumpStartingPointCandidate = -1;
+
+    _buttonsManager.resetEventValues();
 
     glm::vec2 thisPoint;
     int thisPointId;
@@ -311,10 +321,7 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) {
             continue;
         }
 
-        if (!jumpTouchFound && _jumpHasValidTouch && _jumpCurrentTouchId == thisPointId) {
-            // valid if it's an ongoing touch
-            jumpTouchFound = true;
-            jumpTouchUpdate(thisPoint);
+        if (_buttonsManager.processOngoingTouch(thisPoint, thisPointId)) {
             continue;
         }
 
@@ -330,18 +337,16 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) {
             continue;
         }
 
-        if (!jumpTouchFound && idxJumpStartingPointCandidate == -1 && jumpTouchBeginIsValid(thisPoint) &&
-                (!_unusedTouches.count(thisPointId) || _unusedTouches[thisPointId] == JUMP )) {
-            idxJumpStartingPointCandidate = i;
+        if (_buttonsManager.findStartingTouchPointCandidate(thisPoint, thisPointId, i, _unusedTouches)) {
             continue;
         }
 
         if (moveTouchBeginIsValid(thisPoint)) {
             unusedTouchesInEvent[thisPointId] = MOVE;
-        } else if (jumpTouchBeginIsValid(thisPoint)) {
-            unusedTouchesInEvent[thisPointId] = JUMP;
         } else if (viewTouchBeginIsValid(thisPoint))  {
             unusedTouchesInEvent[thisPointId] = VIEW;
+        } else {
+            _buttonsManager.saveUnusedTouches(unusedTouchesInEvent, thisPoint, thisPointId);
         }
 
     }
@@ -370,24 +375,13 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) {
             viewTouchEnd();
         }
     }
-    if (!jumpTouchFound) {
-        if (idxJumpStartingPointCandidate != -1) {
-            _jumpCurrentTouchId = tPoints[idxJumpStartingPointCandidate].id();
-            _unusedTouches.erase(_jumpCurrentTouchId);
-            thisPoint.x = tPoints[idxJumpStartingPointCandidate].pos().x();
-            thisPoint.y = tPoints[idxJumpStartingPointCandidate].pos().y();
-            jumpTouchBegin(thisPoint);
-        } else {
-            if (_jumpHasValidTouch) {
-                jumpTouchEnd();
-            }
-        }
-    }
+
+    _buttonsManager.processBeginOrEnd(thisPoint, tPoints, _unusedTouches);
 
 }
 
 bool TouchscreenVirtualPadDevice::viewTouchBeginIsValid(glm::vec2 touchPoint) {
-    return !moveTouchBeginIsValid(touchPoint) && !jumpTouchBeginIsValid(touchPoint);
+    return !moveTouchBeginIsValid(touchPoint) && _buttonsManager.touchBeginInvalidForAllButtons(touchPoint);
 }
 
 bool TouchscreenVirtualPadDevice::moveTouchBeginIsValid(glm::vec2 touchPoint) {
@@ -400,30 +394,6 @@ bool TouchscreenVirtualPadDevice::moveTouchBeginIsValid(glm::vec2 touchPoint) {
     }
 }
 
-bool TouchscreenVirtualPadDevice::jumpTouchBeginIsValid(glm::vec2 touchPoint) {
-    // position of button and boundaries
-    return glm::distance2(touchPoint, _jumpButtonPosition) < _jumpButtonRadius * _jumpButtonRadius;
-}
-
-void TouchscreenVirtualPadDevice::jumpTouchBegin(glm::vec2 touchPoint) {
-    auto& virtualPadManager = VirtualPad::Manager::instance();
-    if (virtualPadManager.isEnabled() && !virtualPadManager.isHidden()) {
-        _jumpHasValidTouch = true;
-
-        _inputDevice->_buttonPressedMap.insert(TouchButtonChannel::JUMP_BUTTON_PRESS);
-    }
-}
-
-void TouchscreenVirtualPadDevice::jumpTouchUpdate(glm::vec2 touchPoint) {}
-
-void TouchscreenVirtualPadDevice::jumpTouchEnd() {
-    if (_jumpHasValidTouch) {
-        _jumpHasValidTouch = false;
-
-        _inputDevice->_buttonPressedMap.erase(TouchButtonChannel::JUMP_BUTTON_PRESS);
-    }    
-}
-
 void TouchscreenVirtualPadDevice::moveTouchBegin(glm::vec2 touchPoint) {
     auto& virtualPadManager = VirtualPad::Manager::instance();
     if (virtualPadManager.isEnabled() && !virtualPadManager.isHidden()) {
@@ -498,7 +468,8 @@ controller::Input::NamedVector TouchscreenVirtualPadDevice::InputDevice::getAvai
         Input::NamedPair(makeInput(TouchAxisChannel::LY), "LY"),
         Input::NamedPair(makeInput(TouchAxisChannel::RX), "RX"),
         Input::NamedPair(makeInput(TouchAxisChannel::RY), "RY"),
-        Input::NamedPair(makeInput(TouchButtonChannel::JUMP_BUTTON_PRESS), "JUMP_BUTTON_PRESS")
+        Input::NamedPair(makeInput(TouchButtonChannel::JUMP), "JUMP_BUTTON_PRESS"),
+        Input::NamedPair(makeInput(TouchButtonChannel::RB), "RB")
     };
     return availableInputs;
 }
@@ -507,3 +478,146 @@ QString TouchscreenVirtualPadDevice::InputDevice::getDefaultMappingConfig() cons
     static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/touchscreenvirtualpad.json";
     return MAPPING_JSON;
 }
+
+TouchscreenVirtualPadDevice::TouchscreenButton::TouchscreenButton(
+        TouchscreenVirtualPadDevice::TouchButtonChannel channelIn,
+        TouchscreenVirtualPadDevice::TouchType touchTypeIn, float buttonRadiusIn,
+        glm::vec2 buttonPositionIn, std::shared_ptr<InputDevice> inputDeviceIn) :
+    buttonPosition(buttonPositionIn),
+    buttonRadius(buttonRadiusIn),
+    touchType(touchTypeIn),
+    channel(channelIn),
+    _inputDevice(inputDeviceIn)
+{
+}
+
+void TouchscreenVirtualPadDevice::TouchscreenButton::touchBegin(glm::vec2 touchPoint) {
+    auto& virtualPadManager = VirtualPad::Manager::instance();
+    if (virtualPadManager.isEnabled() && !virtualPadManager.isHidden()) {
+        hasValidTouch = true;
+
+        _inputDevice->_buttonPressedMap.insert(channel);
+    }
+}
+
+void TouchscreenVirtualPadDevice::TouchscreenButton::touchUpdate(glm::vec2 touchPoint) {
+
+}
+
+void TouchscreenVirtualPadDevice::TouchscreenButton::touchEnd() {
+    if (hasValidTouch) {
+        hasValidTouch = false;
+
+        _inputDevice->_buttonPressedMap.erase(channel);
+    }
+}
+
+bool TouchscreenVirtualPadDevice::TouchscreenButton::touchBeginIsValid(glm::vec2 touchPoint) {
+    return glm::distance2(touchPoint, buttonPosition) < buttonRadius * buttonRadius;
+}
+
+void TouchscreenVirtualPadDevice::TouchscreenButton::resetEventValues() {
+    _candidatePointIdx = -1;
+    _found = false;
+}
+
+TouchscreenVirtualPadDevice::TouchscreenButtonsManager::TouchscreenButtonsManager() {}
+
+void TouchscreenVirtualPadDevice::TouchscreenButtonsManager::addButton(
+        TouchscreenVirtualPadDevice::TouchscreenButton button) {
+    buttons.push_back(button);
+}
+
+void TouchscreenVirtualPadDevice::TouchscreenButtonsManager::resetEventValues() {
+    for(int i = 0; i < buttons.size(); i++) {
+        TouchscreenButton &button = buttons[i];
+        button.resetEventValues();
+    }
+}
+
+bool
+TouchscreenVirtualPadDevice::TouchscreenButtonsManager::processOngoingTouch(glm::vec2 thisPoint,
+                                                                            int thisPointId) {
+    for(int i = 0; i < buttons.size(); i++) {
+        TouchscreenButton &button = buttons[i];
+
+        if (!button._found && button.hasValidTouch && button.currentTouchId == thisPointId) {
+            // valid if it's an ongoing touch
+            button._found = true;
+            button.touchUpdate(thisPoint);
+            return true;
+        }
+    }
+    return false;
+
+}
+
+bool TouchscreenVirtualPadDevice::TouchscreenButtonsManager::findStartingTouchPointCandidate(
+        glm::vec2 thisPoint, int thisPointId, int thisPointIdx, std::map<int, TouchType> &globalUnusedTouches) {
+
+    for(int i = 0; i < buttons.size(); i++) {
+        TouchscreenButton &button = buttons[i];
+        if (!button._found && button._candidatePointIdx == -1 && button.touchBeginIsValid(thisPoint)) {
+            if (!globalUnusedTouches.count(thisPointId) ) {
+                button._candidatePointIdx = thisPointIdx;
+                return true;
+            } else if (globalUnusedTouches[thisPointId] == button.touchType) {
+                button._candidatePointIdx = thisPointIdx;
+                return true;
+            }
+        }
+    }
+    return false;
+
+}
+
+void TouchscreenVirtualPadDevice::TouchscreenButtonsManager::saveUnusedTouches(
+        std::map<int, TouchscreenVirtualPadDevice::TouchType> &unusedTouchesInEvent, glm::vec2 thisPoint,
+        int thisPointId) {
+    for(int i = 0; i < buttons.size(); i++) {
+        TouchscreenButton &button = buttons[i];
+        if (button.touchBeginIsValid(thisPoint)) {
+            unusedTouchesInEvent[thisPointId] = button.touchType;
+            return;
+        }
+    }
+
+}
+
+void TouchscreenVirtualPadDevice::TouchscreenButtonsManager::processBeginOrEnd(
+        glm::vec2 thisPoint, const QList<QTouchEvent::TouchPoint> &tPoints, std::map<int, TouchType> globalUnusedTouches) {
+    for(int i = 0; i < buttons.size(); i++) {
+        TouchscreenButton &button = buttons[i];
+        if (!button._found) {
+            if (button._candidatePointIdx != -1) {
+                button.currentTouchId = tPoints[button._candidatePointIdx].id();
+                globalUnusedTouches.erase(button.currentTouchId);
+                thisPoint.x = tPoints[button._candidatePointIdx].pos().x();
+                thisPoint.y = tPoints[button._candidatePointIdx].pos().y();
+                button.touchBegin(thisPoint);
+            } else {
+                if (button.hasValidTouch) {
+                    button.touchEnd();
+                }
+            }
+        }
+    }
+
+}
+
+void TouchscreenVirtualPadDevice::TouchscreenButtonsManager::endTouchForAll() {
+    for(int i = 0; i < buttons.size(); i++) {
+        TouchscreenButton &button = buttons[i];
+        button.touchEnd();
+    }
+}
+
+bool TouchscreenVirtualPadDevice::TouchscreenButtonsManager::touchBeginInvalidForAllButtons(glm::vec2 touchPoint) {
+    for(int i = 0; i < buttons.size(); i++) {
+        TouchscreenButton &button = buttons[i];
+        if (button.touchBeginIsValid(touchPoint)) {
+            return false;
+        }
+    }
+    return true;
+}
diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h
index ef1e7a4d89..4ef1dbd4f6 100644
--- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h
+++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h
@@ -15,6 +15,7 @@
 #include <controllers/InputDevice.h>
 #include "InputPlugin.h"
 #include <QtGui/qtouchdevice.h>
+#include <QtGui/QList>
 #include "VirtualPadManager.h"
 
 class QTouchEvent;
@@ -51,7 +52,8 @@ public:
     };
 
     enum TouchButtonChannel {
-        JUMP_BUTTON_PRESS
+        JUMP,
+        RB
     };
 
 protected:
@@ -82,7 +84,60 @@ protected:
     enum TouchType {
         MOVE = 1,
         VIEW,
-        JUMP
+        JUMP_BUTTON,
+        RB_BUTTON
+    };
+
+    class TouchscreenButton {
+    public:
+
+        TouchscreenButton() {};
+
+        TouchscreenButton(TouchButtonChannel channelIn, TouchType touchTypeIn, float buttonRadiusIn, glm::vec2 buttonPositionIn,
+                          std::shared_ptr<InputDevice> inputDeviceIn);
+
+        void touchBegin(glm::vec2 touchPoint);
+        void touchUpdate(glm::vec2 touchPoint);
+        void touchEnd();
+        bool touchBeginIsValid(glm::vec2 touchPoint);
+
+        bool hasValidTouch { false };
+        int currentTouchId;
+
+        // per event tmp values
+        int _candidatePointIdx { -1 };
+        bool _found { false };
+        void resetEventValues();
+
+        glm::vec2 buttonPosition;
+        float buttonRadius;
+        TouchType touchType;
+        TouchButtonChannel channel;
+
+        std::shared_ptr<InputDevice> _inputDevice;
+
+    };
+
+    class TouchscreenButtonsManager {
+    public:
+
+        TouchscreenButtonsManager();
+
+        QVector<TouchscreenButton> buttons;
+
+        void addButton(TouchscreenButton button);
+        int buttonsCount() {
+            return buttons.size();
+        }
+
+        void resetEventValues();
+        bool processOngoingTouch(glm::vec2 thisPoint, int thisPointId);
+        bool findStartingTouchPointCandidate(glm::vec2 thisPoint, int thisPointId, int thisPointIdx, std::map<int, TouchType> &globalUnusedTouches);
+        void saveUnusedTouches(std::map<int, TouchType> &unusedTouchesInEvent, glm::vec2 thisPoint, int thisPointId);
+        void processBeginOrEnd(glm::vec2 thisPoint, const QList<QTouchEvent::TouchPoint>& tPoints, std::map<int, TouchType> globalUnusedTouches);
+
+        void endTouchForAll();
+        bool touchBeginInvalidForAllButtons(glm::vec2 touchPoint);
     };
 
     float _lastPinchScale;
@@ -101,9 +156,6 @@ protected:
     glm::vec2 _viewCurrentTouchPoint;
     int _viewCurrentTouchId;
 
-    bool _jumpHasValidTouch;
-    int _jumpCurrentTouchId;
-
     std::map<int, TouchType> _unusedTouches;
 
     int _touchPointCount;
@@ -116,8 +168,9 @@ protected:
     float _fixedRadiusForCalc;
     int _extraBottomMargin {0};
 
-    glm::vec2 _jumpButtonPosition;
-    float _jumpButtonRadius;
+    float _buttonRadius;
+
+    TouchscreenButtonsManager _buttonsManager;
 
     void moveTouchBegin(glm::vec2 touchPoint);
     void moveTouchUpdate(glm::vec2 touchPoint);
@@ -129,11 +182,6 @@ protected:
     void viewTouchEnd();
     bool viewTouchBeginIsValid(glm::vec2 touchPoint);
 
-    void jumpTouchBegin(glm::vec2 touchPoint);
-    void jumpTouchUpdate(glm::vec2 touchPoint);
-    void jumpTouchEnd();
-    bool jumpTouchBeginIsValid(glm::vec2 touchPoint);
-
     void setupControlsPositions(VirtualPad::Manager& virtualPadManager, bool force = false);
 
     void processInputDeviceForMove(VirtualPad::Manager& virtualPadManager);
diff --git a/libraries/ui/src/VirtualPadManager.cpp b/libraries/ui/src/VirtualPadManager.cpp
index ef2b8670cc..bf325a0bd6 100644
--- a/libraries/ui/src/VirtualPadManager.cpp
+++ b/libraries/ui/src/VirtualPadManager.cpp
@@ -38,10 +38,10 @@ namespace VirtualPad {
     const float Manager::BASE_DIAMETER_PIXELS = 512.0f;
     const float Manager::BASE_MARGIN_PIXELS = 59.0f;
     const float Manager::STICK_RADIUS_PIXELS = 105.0f;
-    const float Manager::JUMP_BTN_TRIMMED_RADIUS_PIXELS = 67.0f;
-    const float Manager::JUMP_BTN_FULL_PIXELS = 164.0f;
-    const float Manager::JUMP_BTN_BOTTOM_MARGIN_PIXELS = 80.0f;
-    const float Manager::JUMP_BTN_RIGHT_MARGIN_PIXELS = 13.0f;
+    const float Manager::BTN_TRIMMED_RADIUS_PIXELS = 67.0f;
+    const float Manager::BTN_FULL_PIXELS = 164.0f;
+    const float Manager::BTN_BOTTOM_MARGIN_PIXELS = 80.0f;
+    const float Manager::BTN_RIGHT_MARGIN_PIXELS = 13.0f;
 
     Manager::Manager() {
 
@@ -76,14 +76,6 @@ namespace VirtualPad {
         _extraBottomMargin = margin;
     }
 
-    glm::vec2 Manager::getJumpButtonPosition() {
-        return _jumpButtonPosition;
-    }
-
-    void Manager::setJumpButtonPosition(glm::vec2 point) {
-        _jumpButtonPosition = point;
-    }
-
     void Manager::requestHapticFeedback(int duration) {
         emit hapticFeedbackRequested(duration);
     }
@@ -92,6 +84,17 @@ namespace VirtualPad {
         return &_leftVPadInstance;
     }
 
+    glm::vec2 Manager::getButtonPosition(Manager::Button button) {
+        if (_buttonsPositions.count(button)) {
+            return _buttonsPositions.at(button);
+        }
+        return glm::vec2();
+    }
+
+    void Manager::setButtonPosition(Manager::Button button, glm::vec2 point) {
+        _buttonsPositions[button] = point;
+    }
+
     bool Instance::isShown() {
         return _shown;
     }
diff --git a/libraries/ui/src/VirtualPadManager.h b/libraries/ui/src/VirtualPadManager.h
index 3c3aa9ec9f..a1f2e17597 100644
--- a/libraries/ui/src/VirtualPadManager.h
+++ b/libraries/ui/src/VirtualPadManager.h
@@ -44,28 +44,35 @@ namespace VirtualPad {
         void hide(bool hide);
         int extraBottomMargin();
         void setExtraBottomMargin(int margin);
-        glm::vec2 getJumpButtonPosition();
-        void setJumpButtonPosition(glm::vec2 point);
+
+        enum Button {
+            JUMP,
+            HANDSHAKE
+        };
+
+        glm::vec2 getButtonPosition(Button button);
+        void setButtonPosition(Button button, glm::vec2 point);
+
         void requestHapticFeedback(int duration);
 
         static const float DPI;
         static const float BASE_DIAMETER_PIXELS;
         static const float BASE_MARGIN_PIXELS;
         static const float STICK_RADIUS_PIXELS;
-        static const float JUMP_BTN_TRIMMED_RADIUS_PIXELS;
-        static const float JUMP_BTN_FULL_PIXELS;
-        static const float JUMP_BTN_BOTTOM_MARGIN_PIXELS;
-        static const float JUMP_BTN_RIGHT_MARGIN_PIXELS;
+        static const float BTN_TRIMMED_RADIUS_PIXELS;
+        static const float BTN_FULL_PIXELS;
+        static const float BTN_BOTTOM_MARGIN_PIXELS;
+        static const float BTN_RIGHT_MARGIN_PIXELS;
 
     signals:
         void hapticFeedbackRequested(int duration);
 
     private:
         Instance _leftVPadInstance;
-        bool _enabled {true};
+        bool _enabled { true };
         bool _hidden;
-        glm::vec2 _jumpButtonPosition;
-        int _extraBottomMargin {0};
+        int _extraBottomMargin { 0 };
+        std::map<Button, glm::vec2> _buttonsPositions;
     };
 }
 
diff --git a/scripts/+android_interface/defaultScripts.js b/scripts/+android_interface/defaultScripts.js
index e6971f5a6b..8b3082d81a 100644
--- a/scripts/+android_interface/defaultScripts.js
+++ b/scripts/+android_interface/defaultScripts.js
@@ -16,7 +16,8 @@ var DEFAULT_SCRIPTS_COMBINED = [
     "system/+android_interface/touchscreenvirtualpad.js",
     "system/+android_interface/actionbar.js",
     "system/+android_interface/audio.js" ,
-    "system/+android_interface/modes.js"/*,
+    "system/+android_interface/modes.js",
+    "system/makeUserConnection.js"/*,
     "system/away.js",
     "system/controllers/controllerDisplayManager.js",
     "system/controllers/handControllerGrabAndroid.js",