diff --git a/android/app/build.gradle b/android/app/build.gradle
index a2f008beef..97267258e2 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -23,7 +23,7 @@ android {
'-DRELEASE_NUMBER=' + RELEASE_NUMBER,
'-DRELEASE_TYPE=' + RELEASE_TYPE,
'-DBUILD_BRANCH=' + BUILD_BRANCH,
- '-DDISABLE_QML=ON',
+ '-DDISABLE_QML=OFF',
'-DDISABLE_KTX_CACHE=OFF'
}
}
diff --git a/interface/resources/icons/+android/backward.svg b/interface/resources/icons/+android/backward.svg
new file mode 100644
index 0000000000..ae0893fc66
--- /dev/null
+++ b/interface/resources/icons/+android/backward.svg
@@ -0,0 +1,70 @@
+
+
+
+
\ No newline at end of file
diff --git a/interface/resources/icons/+android/forward.svg b/interface/resources/icons/+android/forward.svg
new file mode 100644
index 0000000000..d03c4097d7
--- /dev/null
+++ b/interface/resources/icons/+android/forward.svg
@@ -0,0 +1,71 @@
+
+
+
+
\ No newline at end of file
diff --git a/interface/resources/icons/+android/go-a.svg b/interface/resources/icons/+android/go-a.svg
new file mode 100755
index 0000000000..faecb15292
--- /dev/null
+++ b/interface/resources/icons/+android/go-a.svg
@@ -0,0 +1,40 @@
+
+
+
+
diff --git a/interface/resources/icons/+android/go-i.svg b/interface/resources/icons/+android/go-i.svg
new file mode 100644
index 0000000000..0f1298d573
--- /dev/null
+++ b/interface/resources/icons/+android/go-i.svg
@@ -0,0 +1,40 @@
+
+
+
+
diff --git a/interface/resources/icons/+android/goto-a.svg b/interface/resources/icons/+android/goto-a.svg
new file mode 100755
index 0000000000..5fb3e52e4c
--- /dev/null
+++ b/interface/resources/icons/+android/goto-a.svg
@@ -0,0 +1,28 @@
+
+
+
+
diff --git a/interface/resources/icons/+android/goto-i.svg b/interface/resources/icons/+android/goto-i.svg
new file mode 100644
index 0000000000..7613beb9e7
--- /dev/null
+++ b/interface/resources/icons/+android/goto-i.svg
@@ -0,0 +1,28 @@
+
+
+
+
diff --git a/interface/resources/icons/+android/hide.svg b/interface/resources/icons/+android/hide.svg
new file mode 100644
index 0000000000..e09d517b08
--- /dev/null
+++ b/interface/resources/icons/+android/hide.svg
@@ -0,0 +1,947 @@
+
+
+
+
diff --git a/interface/resources/icons/+android/home.svg b/interface/resources/icons/+android/home.svg
new file mode 100644
index 0000000000..414c179e79
--- /dev/null
+++ b/interface/resources/icons/+android/home.svg
@@ -0,0 +1,82 @@
+
+
+
+
\ No newline at end of file
diff --git a/interface/resources/icons/+android/show-up.svg b/interface/resources/icons/+android/show-up.svg
new file mode 100644
index 0000000000..0736b9a794
--- /dev/null
+++ b/interface/resources/icons/+android/show-up.svg
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/interface/resources/qml/+android/AddressBarDialog.qml b/interface/resources/qml/+android/AddressBarDialog.qml
new file mode 100644
index 0000000000..e07af24b8d
--- /dev/null
+++ b/interface/resources/qml/+android/AddressBarDialog.qml
@@ -0,0 +1,230 @@
+//
+// AddressBarDialog.qml
+//
+// Created by Austin Davis on 2015/04/14
+// Copyright 2015 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+import Hifi 1.0
+import QtQuick 2.4
+import "../controls"
+import "../styles"
+import "../hifi" as QmlHifi
+import "../hifi/toolbars"
+import "../styles-uit" as HifiStyles
+import "../controls-uit" as HifiControls
+
+Item {
+ QmlHifi.HifiConstants { id: android }
+
+ width: parent ? parent.width - android.dimen.windowLessWidth : 0
+ height: parent ? parent.height - android.dimen.windowLessHeight : 0
+ z: android.dimen.windowZ
+ anchors { horizontalCenter: parent.horizontalCenter; bottom: parent.bottom }
+
+ id: bar
+ property bool isCursorVisible: false // Override default cursor visibility.
+ property bool shown: true
+
+ onShownChanged: {
+ bar.visible = shown;
+ sendToScript({method: 'shownChanged', params: { shown: shown }});
+ if (shown) {
+ updateLocationText(false);
+ }
+ }
+
+ function hide() {
+ shown = false;
+ sendToScript ({ type: "hide" });
+ }
+
+ Component.onCompleted: {
+ updateLocationText(false);
+ }
+
+ HifiConstants { id: hifi }
+ HifiStyles.HifiConstants { id: hifiStyleConstants }
+
+ signal sendToScript(var message);
+
+ AddressBarDialog {
+ id: addressBarDialog
+ }
+
+
+ Rectangle {
+ id: background
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: android.color.gradientTop }
+ GradientStop { position: 1.0; color: android.color.gradientBottom }
+ }
+ anchors {
+ fill: parent
+ }
+
+ QmlHifi.WindowHeader {
+ id: header
+ iconSource: "../../../icons/goto-i.svg"
+ titleText: "GO TO"
+ }
+
+ HifiStyles.RalewayRegular {
+ id: notice
+ text: "YOUR LOCATION"
+ font.pixelSize: hifi.fonts.pixelSize * 2.15;
+ color: "#2CD7FF"
+ anchors {
+ bottom: addressBackground.top
+ bottomMargin: 45
+ left: addressBackground.left
+ leftMargin: 60
+ }
+
+ }
+
+ property int inputAreaHeight: 210
+ property int inputAreaStep: (height - inputAreaHeight) / 2
+
+ ToolbarButton {
+ id: homeButton
+ y: 280
+ imageURL: "../../icons/home.svg"
+ onClicked: {
+ addressBarDialog.loadHome();
+ bar.shown = false;
+ }
+ anchors {
+ leftMargin: 75
+ left: parent.left
+ }
+ size: 150
+ }
+
+ ToolbarButton {
+ id: backArrow;
+ imageURL: "../../icons/backward.svg";
+ onClicked: addressBarDialog.loadBack();
+ anchors {
+ left: homeButton.right
+ leftMargin: 70
+ verticalCenter: homeButton.verticalCenter
+ }
+ size: 150
+ }
+ ToolbarButton {
+ id: forwardArrow;
+ imageURL: "../../icons/forward.svg";
+ onClicked: addressBarDialog.loadForward();
+ anchors {
+ left: backArrow.right
+ leftMargin: 60
+ verticalCenter: homeButton.verticalCenter
+ }
+ size: 150
+ }
+
+ HifiStyles.FiraSansRegular {
+ id: location;
+ font.pixelSize: addressLine.font.pixelSize;
+ color: "gray";
+ clip: true;
+ anchors.fill: addressLine;
+ visible: addressLine.text.length === 0
+ z: 1
+ }
+
+ Rectangle {
+ id: addressBackground
+ x: 780
+ y: 280
+ width: 1440
+ height: 150
+ color: "#FFFFFF"
+ }
+
+ TextInput {
+ id: addressLine
+ focus: true
+ x: 870
+ y: 450
+ width: 1350
+ height: 120
+ inputMethodHints: Qt.ImhNoPredictiveText
+ //helperText: "Hint is here"
+ anchors {
+ verticalCenter: homeButton.verticalCenter
+ }
+ font.pixelSize: hifi.fonts.pixelSize * 3.75
+ onTextChanged: {
+ //filterChoicesByText();
+ updateLocationText(addressLine.text.length > 0);
+ if (!isCursorVisible && text.length > 0) {
+ isCursorVisible = true;
+ cursorVisible = true;
+ }
+ }
+
+ onActiveFocusChanged: {
+ //cursorVisible = isCursorVisible && focus;
+ }
+ }
+
+
+
+ function toggleOrGo() {
+ if (addressLine.text !== "") {
+ addressBarDialog.loadAddress(addressLine.text);
+ }
+ bar.shown = false;
+ }
+
+ Keys.onPressed: {
+ switch (event.key) {
+ case Qt.Key_Escape:
+ case Qt.Key_Back:
+ clearAddressLineTimer.start();
+ event.accepted = true
+ bar.shown = false;
+ break
+ case Qt.Key_Enter:
+ case Qt.Key_Return:
+ toggleOrGo();
+ clearAddressLineTimer.start();
+ event.accepted = true
+ break
+ }
+ }
+
+ }
+
+ Timer {
+ // Delay clearing address line so as to avoid flicker of "not connected" being displayed after entering an address.
+ id: clearAddressLineTimer
+ running: false
+ interval: 100 // ms
+ repeat: false
+ onTriggered: {
+ addressLine.text = "";
+ isCursorVisible = false;
+ }
+ }
+
+ function updateLocationText(enteringAddress) {
+ if (enteringAddress) {
+ notice.text = "Go to a place, @user, path or network address";
+ notice.color = "#ffffff"; // hifiStyleConstants.colors.baseGrayHighlight;
+ location.visible = false;
+ } else {
+ notice.text = AddressManager.isConnected ? "YOUR LOCATION:" : "NOT CONNECTED";
+ notice.color = AddressManager.isConnected ? hifiStyleConstants.colors.turquoise : hifiStyleConstants.colors.redHighlight;
+ // Display hostname, which includes ip address, localhost, and other non-placenames.
+ location.text = (AddressManager.placename || AddressManager.hostname || '') + (AddressManager.pathname ? AddressManager.pathname.match(/\/[^\/]+/)[0] : '');
+ location.visible = true;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/interface/resources/qml/hifi/+android/HifiConstants.qml b/interface/resources/qml/hifi/+android/HifiConstants.qml
new file mode 100644
index 0000000000..ee6d92ed38
--- /dev/null
+++ b/interface/resources/qml/hifi/+android/HifiConstants.qml
@@ -0,0 +1,54 @@
+//
+// HifiAndroidConstants.qml
+// interface/resources/qml/+android
+//
+// Created by Gabriel Calero & Cristian Duarte on 23 Oct 2017
+// Copyright 2017 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+import QtQuick 2.4
+
+Item {
+
+ id: android
+
+ readonly property alias dimen: dimen
+ readonly property alias color: color
+
+ Item {
+ id: dimen
+ readonly property real windowLessWidth: 126
+ readonly property real windowLessHeight: 64
+
+ readonly property real windowZ: 100
+
+ readonly property real headerHeight: 276
+
+ readonly property real headerIconPosX: 90
+ readonly property real headerIconPosY: 108
+ readonly property real headerIconWidth: 111
+ readonly property real headerIconHeight: 111
+ readonly property real headerIconTitleDistance: 151
+
+ readonly property real headerHideWidth: 150
+ readonly property real headerHideHeight: 150
+ readonly property real headerHideRightMargin: 110
+ readonly property real headerHideTopMargin: 90
+ readonly property real headerHideIconWidth: 70
+ readonly property real headerHideIconHeight: 45
+ readonly property real headerHideTextTopMargin: 36
+
+ readonly property real botomHudWidth: 366
+ readonly property real botomHudHeight: 180
+
+ }
+
+ Item {
+ id: color
+ readonly property color gradientTop: "#4E4E4E"
+ readonly property color gradientBottom: "#242424"
+ }
+}
diff --git a/interface/resources/qml/hifi/+android/WindowHeader.qml b/interface/resources/qml/hifi/+android/WindowHeader.qml
new file mode 100644
index 0000000000..4ec0a0c6e6
--- /dev/null
+++ b/interface/resources/qml/hifi/+android/WindowHeader.qml
@@ -0,0 +1,113 @@
+//
+// WindowHeader.qml
+// interface/resources/qml/android
+//
+// Created by Gabriel Calero & Cristian Duarte on 23 Oct 2017
+// Copyright 2017 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+import QtQuick 2.5
+import QtQuick.Controls 1.4
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Layouts 1.3
+import Qt.labs.settings 1.0
+import "."
+import "../styles" as HifiStyles
+import "../styles-uit"
+import "../controls-uit" as HifiControlsUit
+import "../controls" as HifiControls
+import ".."
+
+
+// header
+Rectangle {
+ id: header
+
+ // properties
+ property string iconSource: ""
+ property string titleText: ""
+ property var extraItemInCenter: Item {}
+
+ HifiStyles.HifiConstants { id: hifiStylesConstants }
+
+ /*property var mockRectangle: Rectangle {
+ anchors.fill: parent
+ color: "#44FFFF00"
+ }*/
+ color: "#00000000"
+ //color: "#55FF0000"
+ width: parent.width
+ height: android.dimen.headerHeight
+ anchors.top : parent.top
+
+ Image {
+ id: windowIcon
+ source: iconSource
+ x: android.dimen.headerIconPosX
+ y: android.dimen.headerIconPosY
+ width: android.dimen.headerIconWidth
+ height: android.dimen.headerIconHeight
+ }
+
+ /*HifiStylesUit.*/FiraSansSemiBold {
+ id: windowTitle
+ x: windowIcon.x + android.dimen.headerIconTitleDistance
+ anchors.verticalCenter: windowIcon.verticalCenter
+ text: titleText
+ color: "#FFFFFF"
+ font.letterSpacing: 2
+ font.pixelSize: hifiStylesConstants.fonts.headerPixelSize * 2.15
+ }
+ Item {
+ height: 60
+ anchors {
+ left: windowTitle.right
+ right: hideButton.left
+ verticalCenter: windowIcon.verticalCenter
+ }
+ children: [ extraItemInCenter/*, mockRectangle */]
+ }
+
+ Rectangle {
+ id: hideButton
+ height: android.dimen.headerHideWidth
+ width: android.dimen.headerHideHeight
+ color: "#00000000"
+ //color: "#CC00FF00"
+ anchors {
+ top: parent.top
+ right: parent.right
+ rightMargin: android.dimen.headerHideRightMargin
+ topMargin: android.dimen.headerHideTopMargin
+ }
+ Image {
+ id: hideIcon
+ source: "../../../icons/hide.svg"
+ width: android.dimen.headerHideIconWidth
+ height: android.dimen.headerHideIconHeight
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ }
+ }
+ /*HifiStyles.*/FiraSansRegular {
+ anchors {
+ top: hideIcon.bottom
+ horizontalCenter: hideIcon.horizontalCenter
+ topMargin: android.dimen.headerHideTextTopMargin
+ }
+ text: "HIDE"
+ color: "#FFFFFF"
+ font.pixelSize: hifiStylesConstants.fonts.pixelSize * 2.15
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ hide();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/interface/resources/qml/hifi/+android/bottomHudOptions.qml b/interface/resources/qml/hifi/+android/bottomHudOptions.qml
new file mode 100644
index 0000000000..860298149f
--- /dev/null
+++ b/interface/resources/qml/hifi/+android/bottomHudOptions.qml
@@ -0,0 +1,89 @@
+//
+// bottomHudOptions.qml
+// interface/resources/qml/android
+//
+// Created by Cristian Duarte & Gabriel Calero on 24 Nov 2017
+// Copyright 2017 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+import Hifi 1.0
+import QtQuick 2.5
+import QtQuick.Controls 1.4
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Layouts 1.3
+import Qt.labs.settings 1.0
+import "../../styles" as HifiStyles
+import "../../styles-uit"
+import "../../controls-uit" as HifiControlsUit
+import "../../controls" as HifiControls
+import ".."
+import "."
+
+Item {
+ id: bottomHud
+
+ property bool shown: false
+
+ signal sendToScript(var message);
+
+ HifiConstants { id: android }
+
+ onShownChanged: {
+ bottomHud.visible = shown;
+ }
+
+ function hide() {
+ shown = false;
+ }
+
+ Rectangle {
+ anchors.fill : parent
+ color: "transparent"
+ Flow {
+ id: flowMain
+ spacing: 0
+ flow: Flow.LeftToRight
+ layoutDirection: Flow.LeftToRight
+ anchors.fill: parent
+ anchors.margins: 12
+
+ Rectangle {
+ id: hideButton
+ height: android.dimen.headerHideWidth
+ width: android.dimen.headerHideHeight
+ color: "#00000000"
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ }
+ Image {
+ id: hideIcon
+ source: "../../../icons/show-up.svg"
+ width: android.dimen.headerHideIconWidth
+ height: android.dimen.headerHideIconHeight
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ verticalCenter: parent.verticalCenter
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ sendToScript ({ method: "showUpBar" });
+ }
+ }
+ }
+ }
+ }
+
+ Component.onCompleted: {
+ width = android.dimen.botomHudWidth;
+ height = android.dimen.botomHudHeight;
+ x=Window.innerWidth - width;
+ y=Window.innerHeight - height;
+ }
+
+}
diff --git a/interface/resources/qml/hifi/+android/bottombar.qml b/interface/resources/qml/hifi/+android/bottombar.qml
new file mode 100644
index 0000000000..2a34b7fe19
--- /dev/null
+++ b/interface/resources/qml/hifi/+android/bottombar.qml
@@ -0,0 +1,135 @@
+//
+// bottomHudOptions.qml
+// interface/resources/qml/android
+//
+// Created by Gabriel Calero & Cristian Duarte on 19 Jan 2018
+// Copyright 2018 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+import Hifi 1.0
+import QtQuick 2.5
+import QtQuick.Controls 1.4
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Layouts 1.3
+import Qt.labs.settings 1.0
+import "../../styles" as Styles
+import "../../styles-uit"
+import "../../controls-uit" as HifiControlsUit
+import "../../controls" as HifiControls
+import ".."
+import "."
+
+Item {
+ id: bar
+ x:0
+
+ property bool shown: true
+
+ signal sendToScript(var message);
+
+ onShownChanged: {
+ bar.visible = shown;
+ }
+
+ function hide() {
+ //shown = false;
+ sendToScript({ method: "hide" });
+ }
+
+ Styles.HifiConstants { id: hifi }
+ HifiConstants { id: android }
+
+ Rectangle {
+ id: background
+ anchors.fill : parent
+ color: "#FF000000"
+ border.color: "#FFFFFF"
+ anchors.bottomMargin: -1
+ anchors.leftMargin: -1
+ anchors.rightMargin: -1
+ Flow {
+ id: flowMain
+ spacing: 10
+ anchors.fill: parent
+ anchors.topMargin: 12
+ anchors.bottomMargin: 12
+ anchors.rightMargin: 12
+ anchors.leftMargin: 72
+ }
+
+
+ Rectangle {
+ id: hideButton
+ height: android.dimen.headerHideWidth
+ width: android.dimen.headerHideHeight
+ color: "#00000000"
+ anchors {
+ right: parent.right
+ rightMargin: android.dimen.headerHideRightMargin
+ top: parent.top
+ topMargin: android.dimen.headerHideTopMargin
+ }
+
+ Image {
+ id: hideIcon
+ source: "../../../icons/hide.svg"
+ width: android.dimen.headerHideIconWidth
+ height: android.dimen.headerHideIconHeight
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ top: parent.top
+ }
+ }
+ FiraSansRegular {
+ anchors {
+ top: hideIcon.bottom
+ horizontalCenter: hideIcon.horizontalCenter
+ topMargin: 12
+ }
+ text: "HIDE"
+ color: "#FFFFFF"
+ font.pixelSize: hifi.fonts.pixelSize * 2.5;
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ hide();
+ }
+ }
+ }
+ }
+
+ Component.onCompleted: {
+ // put on bottom
+ width = Window.innerWidth;
+ height = 255;
+ y = Window.innerHeight - height;
+ }
+
+ function addButton(properties) {
+ var component = Qt.createComponent("button.qml");
+ if (component.status == Component.Ready) {
+ var button = component.createObject(flowMain);
+ // copy all properites to button
+ var keys = Object.keys(properties).forEach(function (key) {
+ button[key] = properties[key];
+ });
+ return button;
+ } else if( component.status == Component.Error) {
+ console.log("Load button errors " + component.errorString());
+ }
+ }
+
+ function urlHelper(src) {
+ if (src.match(/\bhttp/)) {
+ return src;
+ } else {
+ return "../../../" + src;
+ }
+ }
+
+}
diff --git a/interface/resources/qml/hifi/+android/button.qml b/interface/resources/qml/hifi/+android/button.qml
new file mode 100644
index 0000000000..ec7af2ab92
--- /dev/null
+++ b/interface/resources/qml/hifi/+android/button.qml
@@ -0,0 +1,230 @@
+import QtQuick 2.5
+import QtQuick.Controls 1.4
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Layouts 1.3
+
+Item {
+ id: button
+ property string icon: "icons/edit-icon.svg"
+ property string hoverIcon: button.icon
+ property string activeIcon: button.icon
+ property string activeHoverIcon: button.activeIcon
+ property int stableOrder: 0
+
+ property int iconSize: 165
+ property string text: "."
+ property string hoverText: button.text
+ property string activeText: button.text
+ property string activeHoverText: button.activeText
+
+ property string bgColor: "#ffffff"
+ property string hoverBgColor: button.bgColor
+ property string activeBgColor: button.bgColor
+ property string activeHoverBgColor: button.bgColor
+
+ property real bgOpacity: 0
+ property real hoverBgOpacity: 1
+ property real activeBgOpacity: 0.5
+ property real activeHoverBgOpacity: 1
+
+ property string textColor: "#ffffff"
+ property int textSize: 54
+ property string hoverTextColor: "#ffffff"
+ property string activeTextColor: "#ffffff"
+ property string activeHoverTextColor: "#ffffff"
+ property int bottomMargin: 30
+
+ property bool isEntered: false
+ property double sortOrder: 100
+
+ property bool isActive: false
+
+ signal clicked()
+
+ onIsActiveChanged: {
+ if (button.isEntered) {
+ button.state = (button.isActive) ? "hover active state" : "hover state";
+ } else {
+ button.state = (button.isActive) ? "active state" : "base state";
+ }
+ }
+
+ function editProperties(props) {
+ for (var prop in props) {
+ button[prop] = props[prop];
+ }
+ }
+
+
+ width: 300
+ height: 300
+
+ Rectangle {
+ id: buttonBg
+ color: bgColor
+ opacity: bgOpacity
+ anchors.right: parent.right
+ anchors.rightMargin: 0
+ anchors.left: parent.left
+ anchors.leftMargin: 0
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 0
+ anchors.top: parent.top
+ anchors.topMargin: 0
+ }
+ Image {
+ id: icon
+ width: iconSize
+ height: iconSize
+ anchors.bottom: text.top
+ anchors.bottomMargin: 6
+ anchors.horizontalCenter: parent.horizontalCenter
+ fillMode: Image.Stretch
+ source: urlHelper(button.icon)
+ }
+ FontLoader {
+ id: firaSans
+ source: "../../../fonts/FiraSans-Regular.ttf"
+ }
+ Text {
+ id: text
+ color: "#ffffff"
+ text: button.text
+ font.family: "FiraSans"
+ //font.bold: true
+ font.pixelSize: textSize
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: bottomMargin
+ anchors.horizontalCenter: parent.horizontalCenter
+ horizontalAlignment: Text.AlignHCenter
+ }
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ enabled: true
+ onClicked: {
+ console.log("Bottom bar button clicked!!");
+ /*if (tabletButton.inDebugMode) {
+ if (tabletButton.isActive) {
+ tabletButton.isActive = false;
+ } else {
+ tabletButton.isActive = true;
+ }
+ }*/
+ button.clicked();
+ /*if (tabletRoot) {
+ tabletRoot.playButtonClickSound();
+ }*/
+ }
+ onEntered: {
+ button.isEntered = true;
+ if (button.isActive) {
+ button.state = "hover active state";
+ } else {
+ button.state = "hover state";
+ }
+ }
+ onExited: {
+ button.isEntered = false;
+ if (button.isActive) {
+ button.state = "active state";
+ } else {
+ button.state = "base state";
+ }
+ }
+ }
+ states: [
+ State {
+ name: "hover state"
+
+ PropertyChanges {
+ target: buttonBg
+ //color: "#cfcfcf"
+ //opacity: 1
+ color: button.hoverBgColor
+ opacity: button.hoverBgOpacity
+ }
+
+ PropertyChanges {
+ target: text
+ //color: "#ffffff"
+ color: button.hoverTextColor
+ text: button.hoverText
+ }
+
+ PropertyChanges {
+ target: icon
+ source: urlHelper(button.hoverIcon)
+ }
+ },
+ State {
+ name: "active state"
+
+ PropertyChanges {
+ target: buttonBg
+ //color: "#1fc6a6"
+ //opacity: 1
+ color: button.activeBgColor
+ opacity: button.activeBgOpacity
+ }
+
+ PropertyChanges {
+ target: text
+ //color: "#333333"
+ color: button.activeTextColor
+ text: button.activeText
+ }
+
+ PropertyChanges {
+ target: icon
+ source: urlHelper(button.activeIcon)
+ }
+ },
+ State {
+ name: "hover active state"
+
+ PropertyChanges {
+ target: buttonBg
+ //color: "#ff0000"
+ //opacity: 1
+ color: button.activeHoverBgColor
+ opacity: button.activeHoverBgOpacity
+ }
+
+ PropertyChanges {
+ target: text
+ //color: "#333333"
+ color: button.activeHoverTextColor
+ text: button.activeHoverText
+ }
+
+ PropertyChanges {
+ target: icon
+ source: urlHelper(button.activeHoverIcon)
+ }
+ },
+ State {
+ name: "base state"
+
+ PropertyChanges {
+ target: buttonBg
+ //color: "#9A9A9A"
+ //opacity: 0.1
+ color: button.bgColor
+ opacity: button.bgOpacity
+ }
+
+ PropertyChanges {
+ target: text
+ //color: "#ffffff"
+ color: button.textColor
+ text: button.text
+ }
+
+ PropertyChanges {
+ target: icon
+ source: urlHelper(button.icon)
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 48c15439ab..00c0dd8387 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -138,6 +138,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -5863,6 +5864,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
scriptEngine->registerFunction("OverlayWebWindow", QmlWebWindowClass::constructor);
#endif
scriptEngine->registerFunction("OverlayWindow", QmlWindowClass::constructor);
+ scriptEngine->registerFunction("QmlFragment", QmlFragmentClass::constructor);
scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance());
scriptEngine->registerGlobalObject("DesktopPreviewProvider", DependencyManager::get().data());
diff --git a/libraries/ui/src/QmlFragmentClass.cpp b/libraries/ui/src/QmlFragmentClass.cpp
new file mode 100644
index 0000000000..ff67022305
--- /dev/null
+++ b/libraries/ui/src/QmlFragmentClass.cpp
@@ -0,0 +1,88 @@
+//
+// Created by Gabriel Calero & Cristian Duarte on Aug 25, 2017
+// Copyright 2017 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "QmlFragmentClass.h"
+
+#include
+#include
+#include
+
+#include
+
+#include "OffscreenUi.h"
+
+
+std::mutex QmlFragmentClass::_mutex;
+std::map QmlFragmentClass::_fragments;
+
+QmlFragmentClass::QmlFragmentClass(QString id) :
+ qml(id) {
+}
+// Method called by Qt scripts to create a new bottom menu bar in Android
+QScriptValue QmlFragmentClass::constructor(QScriptContext* context, QScriptEngine* engine) {
+
+ std::lock_guard guard(_mutex);
+ auto qml = context->argument(0).toVariant().toMap().value("qml");
+ if (qml.isValid()) {
+ // look up tabletId in the map.
+ auto iter = _fragments.find(qml.toString());
+ if (iter != _fragments.end()) {
+ //qDebug() << "[QML-ANDROID] QmlFragmentClass menu already exists";
+ return iter->second;
+ }
+ } else {
+ qWarning() << "QmlFragmentClass could not build instance " << qml;
+ return QScriptValue();
+ }
+
+ auto properties = parseArguments(context);
+ auto offscreenUi = DependencyManager::get();
+ QmlFragmentClass* retVal = new QmlFragmentClass(qml.toString());
+ Q_ASSERT(retVal);
+ if (QThread::currentThread() != qApp->thread()) {
+ retVal->moveToThread(qApp->thread());
+ BLOCKING_INVOKE_METHOD(retVal, "initQml", Q_ARG(QVariantMap, properties));
+ } else {
+ retVal->initQml(properties);
+ }
+ connect(engine, &QScriptEngine::destroyed, retVal, &QmlWindowClass::deleteLater);
+ QScriptValue scriptObject = engine->newQObject(retVal);
+ _fragments[qml.toString()] = scriptObject;
+ return scriptObject;
+}
+
+void QmlFragmentClass::close() {
+ QmlWindowClass::close();
+ _fragments.erase(qml);
+}
+
+QObject* QmlFragmentClass::addButton(const QVariant& properties) {
+ QVariant resultVar;
+ Qt::ConnectionType connectionType = Qt::AutoConnection;
+
+ if (QThread::currentThread() != _qmlWindow->thread()) {
+ connectionType = Qt::BlockingQueuedConnection;
+ }
+ bool hasResult = QMetaObject::invokeMethod(_qmlWindow, "addButton", connectionType,
+ Q_RETURN_ARG(QVariant, resultVar), Q_ARG(QVariant, properties));
+ if (!hasResult) {
+ qWarning() << "QmlFragmentClass addButton has no result";
+ return NULL;
+ }
+
+ QObject* qmlButton = qvariant_cast(resultVar);
+ if (!qmlButton) {
+ qWarning() << "QmlFragmentClass addButton result not a QObject";
+ return NULL;
+ }
+
+ return qmlButton;
+}
+
+void QmlFragmentClass::removeButton(QObject* button) {
+}
diff --git a/libraries/ui/src/QmlFragmentClass.h b/libraries/ui/src/QmlFragmentClass.h
new file mode 100644
index 0000000000..87c18a49ad
--- /dev/null
+++ b/libraries/ui/src/QmlFragmentClass.h
@@ -0,0 +1,45 @@
+//
+// Created by Gabriel Calero & Cristian Duarte on Aug 25, 2017
+// Copyright 2017 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi_ui_QmlFragmentClass_h
+#define hifi_ui_QmlFragmentClass_h
+
+#include "QmlWindowClass.h"
+
+class QmlFragmentClass : public QmlWindowClass {
+ Q_OBJECT
+public:
+ QmlFragmentClass(QString id);
+ static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine);
+
+ /**jsdoc
+ * Creates a new button, adds it to this and returns it.
+ * @function QmlFragmentClass#addButton
+ * @param properties {Object} button properties
+ * @returns {TabletButtonProxy}
+ */
+ Q_INVOKABLE QObject* addButton(const QVariant& properties);
+
+ /*
+ * TODO - not yet implemented
+ */
+ Q_INVOKABLE void removeButton(QObject* tabletButtonProxy);
+public slots:
+ Q_INVOKABLE void close();
+
+protected:
+ QString qmlSource() const override { return qml; }
+
+ static std::mutex _mutex;
+ static std::map _fragments;
+private:
+ QString qml;
+
+};
+
+#endif
diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp
index db3df34dc5..a22a5e5a5f 100644
--- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp
+++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp
@@ -28,7 +28,7 @@
#include
#include
#include
-
+#include
#include
#include
#include
@@ -1136,6 +1136,17 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even
}
break;
}
+ case QEvent::InputMethod:
+ case QEvent::InputMethodQuery: {
+ if (_quickWindow && _quickWindow->activeFocusItem()) {
+ event->ignore();
+ if (QCoreApplication::sendEvent(_quickWindow->activeFocusItem(), event)) {
+ return event->isAccepted();
+ }
+ return false;
+ }
+ break;
+ }
#endif
default:
break;
diff --git a/scripts/+android/defaultScripts.js b/scripts/+android/defaultScripts.js
index 54c899d1da..a85b7e2208 100644
--- a/scripts/+android/defaultScripts.js
+++ b/scripts/+android/defaultScripts.js
@@ -13,7 +13,8 @@
var DEFAULT_SCRIPTS_COMBINED = [
"system/progress.js",
- "system/touchscreenvirtualpad.js"/*,
+ "system/touchscreenvirtualpad.js",
+ "system/bottombar.js"/*,
"system/away.js",
"system/controllers/controllerDisplayManager.js",
"system/controllers/handControllerGrabAndroid.js",
diff --git a/scripts/system/bottombar.js b/scripts/system/bottombar.js
new file mode 100644
index 0000000000..064025f392
--- /dev/null
+++ b/scripts/system/bottombar.js
@@ -0,0 +1,159 @@
+"use strict";
+//
+// bottombar.js
+// scripts/system/
+//
+// Created by Gabriel Calero & Cristian Duarte on Jan 18, 2018
+// Copyright 2018 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+(function() { // BEGIN LOCAL_SCOPE
+
+var bottombar;
+var bottomHudOptionsBar;
+var gotoBtn;
+
+var gotoScript = Script.require('./goto-android.js');
+
+var logEnabled = false;
+
+function printd(str) {
+ if (logEnabled) {
+ print("[bottombar.js] " + str);
+ }
+}
+
+function init() {
+ gotoScript.init();
+ gotoScript.setOnShownChange(function (shown) {
+ if (shown) {
+ showAddressBar();
+ } else {
+ hideAddressBar();
+ }
+ });
+
+ setupBottomBar();
+ setupBottomHudOptionsBar();
+
+ raiseBottomBar();
+
+}
+
+function shutdown() {
+}
+
+function setupBottomBar() {
+ bottombar = new QmlFragment({
+ qml: "hifi/bottombar.qml"
+ });
+
+ bottombar.fromQml.connect(function(message) {
+ switch (message.method) {
+ case 'hide':
+ lowerBottomBar();
+ break;
+ default:
+ print('[bottombar.js] Unrecognized message from bottomHud.qml:', JSON.stringify(message));
+ }
+ });
+
+
+ gotoBtn = bottombar.addButton({
+ icon: "icons/goto-i.svg",
+ activeIcon: "icons/goto-a.svg",
+ bgOpacity: 0,
+ hoverBgOpacity: 0,
+ activeBgOpacity: 0,
+ activeHoverBgOpacity: 0,
+ height: 240,
+ width: 300,
+ iconSize: 108,
+ textSize: 45,
+ text: "GO TO"
+ });
+
+ gotoBtn.clicked.connect(function() {
+ if (!gotoScript.isVisible()) {
+ showAddressBar();
+ } else {
+ hideAddressBar();
+ }
+ });
+
+ // TODO: setup all the buttons or provide a dynamic interface
+
+ raiseBottomBar();
+
+
+}
+
+var setupBottomHudOptionsBar = function() {
+ var bottomHud = new QmlFragment({
+ qml: "hifi/bottomHudOptions.qml"
+ });
+
+ bottomHudOptionsBar = {
+ show: function() {
+ bottomHud.setVisible(true);
+ },
+ hide: function() {
+ bottomHud.setVisible(false);
+ },
+ qmlFragment: bottomHud
+ };
+ bottomHud.fromQml.connect(
+ function(message) {
+ switch (message.method) {
+ case 'showUpBar':
+ printd('[bottombar.js] showUpBar message from bottomHudOptions.qml: ', JSON.stringify(message));
+ raiseBottomBar();
+ break;
+ default:
+ print('[bottombar.js] Unrecognized message from bottomHudOptions.qml:', JSON.stringify(message));
+ }
+ }
+ );
+}
+
+function lowerBottomBar() {
+ if (bottombar) {
+ bottombar.setVisible(false);
+ }
+ if (bottomHudOptionsBar) {
+ bottomHudOptionsBar.show();
+ }
+}
+
+function raiseBottomBar() {
+ print('[bottombar.js] raiseBottomBar begin');
+ if (bottombar) {
+ bottombar.setVisible(true);
+ }
+ if (bottomHudOptionsBar) {
+ bottomHudOptionsBar.hide();
+ }
+ print('[bottombar.js] raiseBottomBar end');
+}
+
+function showAddressBar() {
+ gotoScript.show();
+ gotoBtn.isActive = true;
+}
+
+function hideAddressBar() {
+ gotoScript.hide();
+ gotoBtn.isActive = false;
+}
+
+
+
+Script.scriptEnding.connect(function () {
+ shutdown();
+});
+
+init();
+
+}()); // END LOCAL_SCOPE
diff --git a/scripts/system/goto-android.js b/scripts/system/goto-android.js
new file mode 100644
index 0000000000..e917455128
--- /dev/null
+++ b/scripts/system/goto-android.js
@@ -0,0 +1,96 @@
+"use strict";
+//
+// goto-android.js
+// scripts/system/
+//
+// Created by Gabriel Calero & Cristian Duarte on 12 Sep 2017
+// Copyright 2017 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+var window;
+
+
+var logEnabled = false;
+function printd(str) {
+ if (logEnabled)
+ print("[goto-android.js] " + str);
+}
+
+function init() {
+}
+
+function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml.
+ switch (message.method) {
+ case 'shownChanged':
+ if (notifyShownChange) {
+ notifyShownChange(message.params.shown);
+ } ;
+ break;
+ case 'hide':
+ module.exports.hide();
+ module.exports.onHidden();
+ break;
+ default:
+ print('[goto-android.js] Unrecognized message from AddressBarDialog.qml:', JSON.stringify(message));
+ }
+}
+
+function sendToQml(message) {
+ window.sendToQml(message);
+}
+
+var isVisible = false;
+var notifyShownChange;
+module.exports = {
+ init: function() {
+ window = new QmlFragment({
+ qml: "AddressBarDialog.qml",
+ visible: false
+ });
+ },
+ show: function() {
+ Controller.setVPadEnabled(false);
+ if (window) {
+ window.fromQml.connect(fromQml);
+ window.setVisible(true);
+ isVisible = true;
+ }
+ },
+ hide: function() {
+ Controller.setVPadEnabled(true);
+ if (window) {
+ window.fromQml.disconnect(fromQml);
+ window.setVisible(false);
+ }
+ isVisible = false;
+ },
+ destroy: function() {
+ if (window) {
+ window.close();
+ window = null;
+ }
+ },
+ isVisible: function() {
+ return isVisible;
+ },
+ width: function() {
+ return window ? window.size.x : 0;
+ },
+ height: function() {
+ return window ? window.size.y : 0;
+ },
+ position: function() {
+ return window && isVisible ? window.position : null;
+ },
+ setOnShownChange: function(f) {
+ notifyShownChange = f;
+ },
+ onHidden: function() { }
+
+
+};
+
+init();