diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java index 6a89a8a819..b3edd59acc 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java @@ -198,6 +198,7 @@ public class InterfaceActivity extends QtActivity { public void openAndroidActivity(String activityName, boolean backToScene) { switch (activityName) { case "Home": + case "Privacy Policy": case "Login": { Intent intent = new Intent(this, MainActivity.class); intent.putExtra(MainActivity.EXTRA_FRAGMENT, activityName); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0e39e9229f..f0838bae9f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2764,6 +2764,13 @@ void Application::initializeUi() { } if (TouchscreenVirtualPadDevice::NAME == inputPlugin->getName()) { _touchscreenVirtualPadDevice = std::dynamic_pointer_cast(inputPlugin); +#if defined(Q_OS_ANDROID) + auto& virtualPadManager = VirtualPad::Manager::instance(); + connect(&virtualPadManager, &VirtualPad::Manager::hapticFeedbackRequested, + this, []() { + AndroidHelper::instance().performHapticFeedback("CONTEXT_CLICK"); + }); +#endif } } @@ -3766,7 +3773,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) { #if defined(Q_OS_ANDROID) if (event->key() == Qt::Key_Back) { event->accept(); - openAndroidActivity("Home", false); + AndroidHelper::instance().requestActivity("Home", false); } #endif _controllerScriptingInterface->emitKeyReleaseEvent(event); // send events to any registered scripts @@ -6376,8 +6383,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("Wallet", DependencyManager::get().data()); scriptEngine->registerGlobalObject("AddressManager", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("App", this); - qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue); DependencyManager::get()->registerMetaTypes(scriptEngine.data()); @@ -8083,32 +8088,18 @@ void Application::saveNextPhysicsStats(QString filename) { _physicsEngine->saveNextPhysicsStats(filename); } -void Application::openAndroidActivity(const QString& activityName, const bool backToScene) { -#if defined(Q_OS_ANDROID) - AndroidHelper::instance().requestActivity(activityName, backToScene); -#endif -} - -void Application::performHapticFeedback(const QString& feedbackConstant) { -#if defined(Q_OS_ANDROID) - AndroidHelper::instance().performHapticFeedback(feedbackConstant); -#endif -} - #if defined(Q_OS_ANDROID) void Application::enterBackground() { QMetaObject::invokeMethod(DependencyManager::get().data(), "stop", Qt::BlockingQueuedConnection); - //GC: commenting it out until we fix it - //getActiveDisplayPlugin()->deactivate(); + getActiveDisplayPlugin()->deactivate(); } void Application::enterForeground() { QMetaObject::invokeMethod(DependencyManager::get().data(), "start", Qt::BlockingQueuedConnection); - //GC: commenting it out until we fix it - /*if (!getActiveDisplayPlugin() || !getActiveDisplayPlugin()->activate()) { + if (!getActiveDisplayPlugin() || !getActiveDisplayPlugin()->activate()) { qWarning() << "Could not re-activate display plugin"; - }*/ + } } #endif diff --git a/interface/src/Application.h b/interface/src/Application.h index c610d9b19c..24bd6c255b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -406,12 +406,7 @@ public slots: void setIsServerlessMode(bool serverlessDomain); void loadServerlessDomain(QUrl domainURL); - Q_INVOKABLE bool askBeforeSetAvatarUrl(const QString& avatarUrl) { return askToSetAvatarUrl(avatarUrl); } - void updateVerboseLogging(); - Q_INVOKABLE void openAndroidActivity(const QString& activityName, const bool backToScene); - Q_INVOKABLE void performHapticFeedback(const QString& feedbackConstant); - private slots: void onDesktopRootItemCreated(QQuickItem* qmlContext); diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 9c46f9e98a..7dc9dd2137 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -15,12 +15,13 @@ #include #include #include - +#include #include #include #include - +#include +#include "AndroidHelper.h" #include "Application.h" #include "DomainHandler.h" #include "MainWindow.h" @@ -131,6 +132,24 @@ void WindowScriptingInterface::disconnectedFromDomain() { emit domainChanged(QUrl()); } +void WindowScriptingInterface::openUrl(const QUrl& url) { + if (!url.isEmpty()) { + if (url.scheme() == URL_SCHEME_HIFI) { + DependencyManager::get()->handleLookupString(url.toString()); + } else { + // address manager did not handle - ask QDesktopServices to handle + QDesktopServices::openUrl(url); + } + } +} + +void WindowScriptingInterface::openAndroidActivity(const QString& activityName, const bool backToScene) { +#if defined(Q_OS_ANDROID) + AndroidHelper::instance().requestActivity(activityName, backToScene); +#endif +} + + QString fixupPathForMac(const QString& directory) { // On OS X `directory` does not work as expected unless a file is included in the path, so we append a bogus // filename if the directory is valid. diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 0b766d2097..ff03b87bb2 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -504,6 +504,20 @@ public slots: */ int openMessageBox(QString title, QString text, int buttons, int defaultButton); + /**jsdoc + * Open the given resource in the Interface window or in a web browser depending on the url scheme + * @function Window.openUrl + * @param {string} url - The resource to open + */ + void openUrl(const QUrl& url); + + /**jsdoc + * (Android only) Open the requested Activity and optionally back to the scene when the activity is done + * @function Window.openAndroidActivity + * @param {string} activityName - The name of the activity to open. One of "Home", "Login" or "Privacy Policy" + */ + void openAndroidActivity(const QString& activityName, const bool backToScene); + /**jsdoc * Update the content of a message box that was opened with {@link Window.openMessageBox|openMessageBox}. * @function Window.updateMessageBox diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp index 7ee2135325..a8e509b7ce 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp @@ -187,6 +187,13 @@ void TouchscreenVirtualPadDevice::InputDevice::update(float deltaTime, const con _axisStateMap.clear(); } +bool TouchscreenVirtualPadDevice::InputDevice::triggerHapticPulse(float strength, float duration, controller::Hand hand) { + auto& virtualPadManager = VirtualPad::Manager::instance(); + virtualPadManager.requestHapticFeedback(); + return true; +} + + void TouchscreenVirtualPadDevice::InputDevice::focusOutEvent() { } diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h index e7e540b503..ef1e7a4d89 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h @@ -63,6 +63,8 @@ protected: // Device functions virtual controller::Input::NamedVector getAvailableInputs() const override; virtual QString getDefaultMappingConfig() const override; + + virtual bool triggerHapticPulse(float strength, float duration, controller::Hand hand) override; virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override; virtual void focusOutEvent() override; diff --git a/libraries/ui/src/VirtualPadManager.cpp b/libraries/ui/src/VirtualPadManager.cpp index dae19b52c2..e62a439ab8 100644 --- a/libraries/ui/src/VirtualPadManager.cpp +++ b/libraries/ui/src/VirtualPadManager.cpp @@ -84,6 +84,10 @@ namespace VirtualPad { _jumpButtonPosition = point; } + void Manager::requestHapticFeedback() { + emit hapticFeedbackRequested(); + } + Instance* Manager::getLeftVirtualPad() { return &_leftVPadInstance; } diff --git a/libraries/ui/src/VirtualPadManager.h b/libraries/ui/src/VirtualPadManager.h index 6f7fbcc921..f5afde9a64 100644 --- a/libraries/ui/src/VirtualPadManager.h +++ b/libraries/ui/src/VirtualPadManager.h @@ -31,8 +31,8 @@ namespace VirtualPad { }; class Manager : public QObject, public Dependency { + Q_OBJECT SINGLETON_DEPENDENCY - Manager(); Manager(const Manager& other) = delete; public: @@ -46,6 +46,7 @@ namespace VirtualPad { void setExtraBottomMargin(int margin); glm::vec2 getJumpButtonPosition(); void setJumpButtonPosition(glm::vec2 point); + void requestHapticFeedback(); static const float DPI; static const float BASE_DIAMETER_PIXELS; @@ -56,6 +57,9 @@ namespace VirtualPad { static const float JUMP_BTN_BOTTOM_MARGIN_PIXELS; static const float JUMP_BTN_RIGHT_MARGIN_PIXELS; + signals: + void hapticFeedbackRequested(); + private: Instance _leftVPadInstance; bool _enabled; diff --git a/scripts/system/+android/actionbar.js b/scripts/system/+android/actionbar.js index 357e7853e7..8c476933ef 100644 --- a/scripts/system/+android/actionbar.js +++ b/scripts/system/+android/actionbar.js @@ -39,11 +39,11 @@ function init() { } function onBackPressed() { - App.performHapticFeedback("CONTEXT_CLICK"); + Controller.triggerHapticPulse(Controller.findDevice("TouchscreenVirtualPad"), 0.1, 1.0, 0); } function onBackClicked() { - App.openAndroidActivity("Home", false); + Window.openAndroidActivity("Home", false); } diff --git a/scripts/system/+android/audio.js b/scripts/system/+android/audio.js index 5eb13a3198..6e0f0f7b03 100644 --- a/scripts/system/+android/audio.js +++ b/scripts/system/+android/audio.js @@ -49,7 +49,7 @@ function onMuteClicked() { } function onMutePressed() { - App.performHapticFeedback("CONTEXT_CLICK"); + Controller.triggerHapticPulse(Controller.findDevice("TouchscreenVirtualPad"), 0.1, 1.0, 0); } function onMuteToggled() { diff --git a/scripts/system/+android/modes.js b/scripts/system/+android/modes.js index c75377b976..941ecf7422 100644 --- a/scripts/system/+android/modes.js +++ b/scripts/system/+android/modes.js @@ -68,7 +68,7 @@ function shutdown() { } function modeButtonPressed() { - App.performHapticFeedback("CONTEXT_CLICK"); + Controller.triggerHapticPulse(Controller.findDevice("TouchscreenVirtualPad"), 0.1, 1.0, 0); } function modeButtonClicked() { diff --git a/scripts/system/+android/radar.js b/scripts/system/+android/radar.js index 455299dd5f..8d4c462f78 100644 --- a/scripts/system/+android/radar.js +++ b/scripts/system/+android/radar.js @@ -99,7 +99,7 @@ function actionOnObjectFromEvent(event) { var entity = Entities.getEntityProperties( entitiesByOverlayID[rayIntersection.overlayID], [ "sourceUrl" ]); - App.openUrl(entity.sourceUrl); + Window.openUrl(entity.sourceUrl); return true; } } @@ -110,7 +110,7 @@ function actionOnObjectFromEvent(event) { if (rayIntersection.properties.type == "Web") { printd("found web element to " + rayIntersection.properties.sourceUrl); - App.openUrl(rayIntersection.properties.sourceUrl); + Window.openUrl(rayIntersection.properties.sourceUrl); return true; } } diff --git a/unpublishedScripts/marketplace/shapes/modules/createPalette.js b/unpublishedScripts/marketplace/shapes/modules/createPalette.js index 38dad5b827..a7afc8a17e 100644 --- a/unpublishedScripts/marketplace/shapes/modules/createPalette.js +++ b/unpublishedScripts/marketplace/shapes/modules/createPalette.js @@ -466,7 +466,7 @@ CreatePalette = function (side, leftInputs, rightInputs, uiCommandCallback) { if (handJointIndex === NONE) { // Don't display if joint isn't available (yet) to attach to. // User can clear this condition by toggling the app off and back on once avatar finishes loading. - App.log(side, "ERROR: CreatePalette: Hand joint index isn't available!"); + console.log(side, "ERROR: CreatePalette: Hand joint index isn't available!"); return; } diff --git a/unpublishedScripts/marketplace/shapes/modules/groups.js b/unpublishedScripts/marketplace/shapes/modules/groups.js index 3153a622ee..3c96b014dd 100644 --- a/unpublishedScripts/marketplace/shapes/modules/groups.js +++ b/unpublishedScripts/marketplace/shapes/modules/groups.js @@ -180,11 +180,11 @@ Groups = function () { } if (entitiesSelectedCount === 0) { - App.log("ERROR: Groups: Nothing to ungroup!"); + console.log("ERROR: Groups: Nothing to ungroup!"); return; } if (entitiesSelectedCount === 1) { - App.log("ERROR: Groups: Cannot ungroup sole entity!"); + console.log("ERROR: Groups: Cannot ungroup sole entity!"); return; } diff --git a/unpublishedScripts/marketplace/shapes/modules/preload.js b/unpublishedScripts/marketplace/shapes/modules/preload.js index e93ef9ac71..a075a0728c 100644 --- a/unpublishedScripts/marketplace/shapes/modules/preload.js +++ b/unpublishedScripts/marketplace/shapes/modules/preload.js @@ -54,7 +54,7 @@ Preload = (function () { findURLsInObject(items[i]); break; default: - App.log("ERROR: Cannot find URL in item type " + (typeof items[i])); + console.log("ERROR: Cannot find URL in item type " + (typeof items[i])); } } @@ -120,7 +120,7 @@ Preload = (function () { deleteTimer = Script.setTimeout(deleteOverlay, DELETE_INTERVAL); } } else { - App.log("ERROR: Cannot preload asset " + url); + console.log("ERROR: Cannot preload asset " + url); } } diff --git a/unpublishedScripts/marketplace/shapes/modules/selection.js b/unpublishedScripts/marketplace/shapes/modules/selection.js index 955cde6bda..7849469733 100644 --- a/unpublishedScripts/marketplace/shapes/modules/selection.js +++ b/unpublishedScripts/marketplace/shapes/modules/selection.js @@ -654,7 +654,7 @@ SelectionManager = function (side) { try { userData = JSON.parse(userDataString); } catch (e) { - App.log(side, "ERROR: Invalid userData in entity being updated! " + userDataString); + console.log(side, "ERROR: Invalid userData in entity being updated! " + userDataString); } } diff --git a/unpublishedScripts/marketplace/shapes/modules/toolIcon.js b/unpublishedScripts/marketplace/shapes/modules/toolIcon.js index 143d768466..c8ea4d7f8b 100644 --- a/unpublishedScripts/marketplace/shapes/modules/toolIcon.js +++ b/unpublishedScripts/marketplace/shapes/modules/toolIcon.js @@ -108,7 +108,7 @@ ToolIcon = function (side) { if (handJointIndex === -1) { // Don't display if joint isn't available (yet) to attach to. // User can clear this condition by toggling the app off and back on once avatar finishes loading. - App.log(side, "ERROR: ToolIcon: Hand joint index isn't available!"); + console.log(side, "ERROR: ToolIcon: Hand joint index isn't available!"); return; } diff --git a/unpublishedScripts/marketplace/shapes/modules/toolsMenu.js b/unpublishedScripts/marketplace/shapes/modules/toolsMenu.js index 04bb88d040..78cafb4244 100644 --- a/unpublishedScripts/marketplace/shapes/modules/toolsMenu.js +++ b/unpublishedScripts/marketplace/shapes/modules/toolsMenu.js @@ -2929,7 +2929,7 @@ ToolsMenu = function (side, leftInputs, rightInputs, uiCommandCallback) { break; default: - App.log(side, "ERROR: ToolsMenu: Unexpected command! " + command); + console.log(side, "ERROR: ToolsMenu: Unexpected command! " + command); } }; @@ -2946,7 +2946,7 @@ ToolsMenu = function (side, leftInputs, rightInputs, uiCommandCallback) { Settings.setValue(optionsSettings[parameter].key, null); // Delete settings value. break; default: - App.log(side, "ERROR: ToolsMenu: Unexpected command! " + command); + console.log(side, "ERROR: ToolsMenu: Unexpected command! " + command); } } @@ -3199,7 +3199,7 @@ ToolsMenu = function (side, leftInputs, rightInputs, uiCommandCallback) { // Nothing to do. break; default: - App.log(side, "ERROR: ToolsMenu: Unexpected hover item! " + hoveredElementType); + console.log(side, "ERROR: ToolsMenu: Unexpected hover item! " + hoveredElementType); } // Update status variables. @@ -3317,7 +3317,7 @@ ToolsMenu = function (side, leftInputs, rightInputs, uiCommandCallback) { // Nothing to do. break; default: - App.log(side, "ERROR: ToolsMenu: Unexpected hover item! " + hoveredElementType); + console.log(side, "ERROR: ToolsMenu: Unexpected hover item! " + hoveredElementType); } } @@ -3566,7 +3566,7 @@ ToolsMenu = function (side, leftInputs, rightInputs, uiCommandCallback) { if (handJointIndex === NONE) { // Don't display if joint isn't available (yet) to attach to. // User can clear this condition by toggling the app off and back on once avatar finishes loading. - App.log(side, "ERROR: ToolsMenu: Hand joint index isn't available!"); + console.log(side, "ERROR: ToolsMenu: Hand joint index isn't available!"); return; } diff --git a/unpublishedScripts/marketplace/shapes/shapes.js b/unpublishedScripts/marketplace/shapes/shapes.js index bb35d9089e..c68e9927d7 100644 --- a/unpublishedScripts/marketplace/shapes/shapes.js +++ b/unpublishedScripts/marketplace/shapes/shapes.js @@ -1932,7 +1932,7 @@ tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); if (!tablet) { - App.log("ERROR: Tablet not found! App not started."); + console.log("ERROR: Tablet not found! App not started."); return; }