From 9df9cf7a47653fee165ba2fbb5fb6207e2aa714f Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Thu, 7 Dec 2017 17:02:04 -0800 Subject: [PATCH] Adding more libs, ifdefs for android incompatible code --- CMakeLists.txt | 11 ++ android/app/CMakeLists.txt | 3 +- android/app/build.gradle | 3 +- android/app/src/main/AndroidManifest.xml | 4 +- android/app/src/main/cpp/+android/simple.qml | 19 +++ android/app/src/main/cpp/main.cpp | 137 +++++++++++++++--- android/app/src/main/cpp/main.qrc | 1 + .../gvrinterface/InterfaceActivity.java | 42 ++++++ android/app/src/main/res/drawable/icon.png | Bin 0 -> 9914 bytes android/build.gradle | 31 +++- android/build_recipes.md | 64 +++++++- interface/CMakeLists.txt | 8 - libraries/gl/src/gl/Config.h | 8 +- libraries/gl/src/gl/GLHelpers.cpp | 2 +- libraries/gl/src/gl/GLHelpers.h | 5 +- libraries/gl/src/gl/OffscreenGLCanvas.cpp | 27 +++- .../plugins/src/plugins/PluginManager.cpp | 31 ++-- libraries/plugins/src/plugins/PluginManager.h | 2 + .../src/FileScriptingInterface.cpp | 37 +++-- libraries/script-engine/src/ScriptEngine.cpp | 6 +- libraries/ui/CMakeLists.txt | 2 +- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 25 +++- libraries/ui/src/ui/OffscreenQmlSurface.h | 4 +- libraries/ui/src/ui/types/FileTypeProfile.cpp | 2 + libraries/ui/src/ui/types/FileTypeProfile.h | 5 +- .../ui/types/FileTypeRequestInterceptor.cpp | 4 + .../src/ui/types/FileTypeRequestInterceptor.h | 4 + .../ui/src/ui/types/HFWebEngineProfile.cpp | 4 + .../ui/src/ui/types/HFWebEngineProfile.h | 5 +- .../types/HFWebEngineRequestInterceptor.cpp | 4 + .../ui/types/HFWebEngineRequestInterceptor.h | 4 + libraries/ui/src/ui/types/RequestFilters.cpp | 3 + libraries/ui/src/ui/types/RequestFilters.h | 8 +- 33 files changed, 409 insertions(+), 106 deletions(-) create mode 100644 android/app/src/main/cpp/+android/simple.qml create mode 100644 android/app/src/main/java/io/highfidelity/gvrinterface/InterfaceActivity.java create mode 100644 android/app/src/main/res/drawable/icon.png diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c10e714a3..e033efa982 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,17 @@ else() option(BUILD_TESTS "Build tests" ON) endif() +if (ANDROID) + set(PLATFORM_QT_COMPONENTS AndroidExtras WebView) +else () + set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets) +endif () + +foreach(PLATFORM_QT_COMPONENT ${PLATFORM_QT_COMPONENTS}) + list(APPEND PLATFORM_QT_LIBRARIES "Qt5::${PLATFORM_QT_COMPONENT}") +endforeach() + + option(BUILD_INSTALLER "Build installer" ON) MESSAGE(STATUS "Build server: " ${BUILD_SERVER}) diff --git a/android/app/CMakeLists.txt b/android/app/CMakeLists.txt index de6a09dab5..6df17c3dc7 100644 --- a/android/app/CMakeLists.txt +++ b/android/app/CMakeLists.txt @@ -1,6 +1,7 @@ set(TARGET_NAME native-lib) setup_hifi_library(Gui Qml Quick) -link_hifi_libraries(shared networking gl gpu gpu-gles image fbx render-utils physics entities octree) +#link_hifi_libraries(shared networking gl gpu gpu-gles image fbx render-utils physics entities octree audio midi recording controllers script-engine ui) +link_hifi_libraries(shared networking gl ui) target_link_libraries(native-lib android log m) target_opengl() diff --git a/android/app/build.gradle b/android/app/build.gradle index bef13facac..066eb7da3d 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -55,7 +55,6 @@ android { dependencies { implementation 'com.google.vr:sdk-audio:1.80.0' implementation 'com.google.vr:sdk-base:1.80.0' - implementation files('libs/QtAndroid-bundled.jar') - implementation files('libs/QtAndroidBearer-bundled.jar') + implementation fileTree(dir: 'libs', include: ['*.jar']) } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index f439a8bbad..2160f7b591 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,5 +1,5 @@ - + @@ -21,7 +21,7 @@ android:roundIcon="@mipmap/ic_launcher_round"> #include #include -#include +#include +#include +#include + +#include +#include +#include + +#include + +Q_LOGGING_CATEGORY(gpugllogging, "hifi.gl") + +bool checkGLError(const char* name) { + GLenum error = glGetError(); + if (!error) { + return false; + } else { + switch (error) { + case GL_INVALID_ENUM: + qCDebug(gpugllogging) << "GLBackend::" << name << ": An unacceptable value is specified for an enumerated argument.The offending command is ignored and has no other side effect than to set the error flag."; + break; + case GL_INVALID_VALUE: + qCDebug(gpugllogging) << "GLBackend" << name << ": A numeric argument is out of range.The offending command is ignored and has no other side effect than to set the error flag"; + break; + case GL_INVALID_OPERATION: + qCDebug(gpugllogging) << "GLBackend" << name << ": The specified operation is not allowed in the current state.The offending command is ignored and has no other side effect than to set the error flag.."; + break; + case GL_INVALID_FRAMEBUFFER_OPERATION: + qCDebug(gpugllogging) << "GLBackend" << name << ": The framebuffer object is not complete.The offending command is ignored and has no other side effect than to set the error flag."; + break; + case GL_OUT_OF_MEMORY: + qCDebug(gpugllogging) << "GLBackend" << name << ": There is not enough memory left to execute the command.The state of the GL is undefined, except for the state of the error flags, after this error is recorded."; + break; + default: + qCDebug(gpugllogging) << "GLBackend" << name << ": Unknown error: " << error; + break; + } + return true; + } +} + +bool checkGLErrorDebug(const char* name) { + return checkGLError(name); +} int QtMsgTypeToAndroidPriority(QtMsgType type) { @@ -28,35 +71,87 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt __android_log_write(QtMsgTypeToAndroidPriority(type), "Interface", message.toStdString().c_str()); } +void qt_gl_set_global_share_context(QOpenGLContext *context); int main(int argc, char* argv[]) { qInstallMessageHandler(messageHandler); - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - - auto physicsEngine = new PhysicsEngine({}); + QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); QGuiApplication app(argc,argv); app.setOrganizationName("QtProject"); app.setOrganizationDomain("qt-project.org"); app.setApplicationName(QFileInfo(app.applicationFilePath()).baseName()); + QtWebView::initialize(); + qputenv("QSG_RENDERER_DEBUG", (QStringList() << "render" << "build" << "change" << "upload" << "roots" << "dump").join(';').toUtf8()); - auto screen = app.primaryScreen(); - if (screen) { - auto rect = screen->availableGeometry(); - auto size = screen->availableSize(); - auto foo = screen->availableVirtualGeometry(); - auto pixelRatio = screen->devicePixelRatio(); - qDebug() << pixelRatio; - qDebug() << rect.width(); - qDebug() << rect.height(); + OffscreenGLCanvas sharedCanvas; + if (!sharedCanvas.create()) { + qFatal("Unable to create primary offscreen context"); } - QQuickView view; - view.connect(view.engine(), &QQmlEngine::quit, &app, &QCoreApplication::quit); - new QQmlFileSelector(view.engine(), &view); - view.setSource(QUrl("qrc:///simple.qml")); - if (view.status() == QQuickView::Error) - return -1; - view.setResizeMode(QQuickView::SizeRootObjectToView); - view.show(); + qt_gl_set_global_share_context(sharedCanvas.getContext()); + + auto globalContext = QOpenGLContext::globalShareContext(); + bool threadedGlRendering = QOpenGLContext::supportsThreadedOpenGL(); + + GLWindow window; + window.create(); + window.setGeometry(qApp->primaryScreen()->availableGeometry()); + window.createContext(globalContext); + if (!window.makeCurrent()) { + qFatal("Unable to make primary window GL context current"); + } + + GLuint fbo = 0; + glGenFramebuffers(1, &fbo); + + + + ivec2 offscreenSize { 640, 480 }; + + OffscreenQmlSurface::setSharedContext(sharedCanvas.getContext()); + OffscreenQmlSurface* qmlSurface = new OffscreenQmlSurface(); + qmlSurface->create(); + qmlSurface->resize(fromGlm(offscreenSize)); + qmlSurface->load("qrc:///simple.qml"); + qmlSurface->resume(); + + auto discardLambda = qmlSurface->getDiscardLambda(); + + window.showFullScreen(); + QTimer timer; + timer.setInterval(10); + timer.setSingleShot(false); + OffscreenQmlSurface::TextureAndFence currentTextureAndFence; + timer.connect(&timer, &QTimer::timeout, &app, [&]{ + window.makeCurrent(); + glClearColor(0, 1, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + + OffscreenQmlSurface::TextureAndFence newTextureAndFence; + if (qmlSurface->fetchTexture(newTextureAndFence)) { + if (currentTextureAndFence.first) { + discardLambda(currentTextureAndFence.first, currentTextureAndFence.second); + } + currentTextureAndFence = newTextureAndFence; + } + checkGLErrorDebug(__FUNCTION__); + + if (currentTextureAndFence.second) { + glWaitSync((GLsync)currentTextureAndFence.second, 0, GL_TIMEOUT_IGNORED); + glDeleteSync((GLsync)currentTextureAndFence.second); + currentTextureAndFence.second = nullptr; + } + + if (currentTextureAndFence.first) { + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); + glFramebufferTexture(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, currentTextureAndFence.first, 0); + glBlitFramebuffer(0, 0, offscreenSize.x, offscreenSize.y, 100, 100, offscreenSize.x + 100, offscreenSize.y + 100, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + } + + window.swapBuffers(); + window.doneCurrent(); + }); + timer.start(); return app.exec(); } diff --git a/android/app/src/main/cpp/main.qrc b/android/app/src/main/cpp/main.qrc index 27d7679317..81cf8ef111 100644 --- a/android/app/src/main/cpp/main.qrc +++ b/android/app/src/main/cpp/main.qrc @@ -1,5 +1,6 @@ simple.qml + +android/simple.qml diff --git a/android/app/src/main/java/io/highfidelity/gvrinterface/InterfaceActivity.java b/android/app/src/main/java/io/highfidelity/gvrinterface/InterfaceActivity.java new file mode 100644 index 0000000000..aad769de70 --- /dev/null +++ b/android/app/src/main/java/io/highfidelity/gvrinterface/InterfaceActivity.java @@ -0,0 +1,42 @@ +// +// InterfaceActivity.java +// gvr-interface/java +// +// Created by Stephen Birarda on 1/26/15. +// 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 +// + +package io.highfidelity.gvrinterface; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; +import android.view.WindowManager; +import android.util.Log; +import org.qtproject.qt5.android.bindings.QtActivity; + +public class InterfaceActivity extends QtActivity { + + public static native void handleHifiURL(String hifiURLString); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + // Get the intent that started this activity in case we have a hifi:// URL to parse + Intent intent = getIntent(); + if (intent.getAction() == Intent.ACTION_VIEW) { + Uri data = intent.getData(); + + if (data.getScheme().equals("hifi")) { + handleHifiURL(data.toString()); + } + } + + } +} \ No newline at end of file diff --git a/android/app/src/main/res/drawable/icon.png b/android/app/src/main/res/drawable/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..70aaf9b4ed60a80081821907d53086beb249eb3b GIT binary patch literal 9914 zcmbWddpuO%7eBnt%rFyT3Q=grMP5-NQz2*x*%jKL~?6f ziexC%M|SBn$x40ga0Qu-0#%o!=2}H$VTA7fyrmDQ}n4)C1>Eo;iK^^vP3Kd_SMw z39#|RfxX5y0qw(`mbXqcC25Qg-H9CM(6v;5IQ@97|oFbH>4Jh1_)^0;pbeqX-GC0(CQU zLW-zioJuJXKM^{h73`%^tMW0~hk<1&dqNqGu|NP>^?B1sk@v?!*yqHB!lrNt4)QNv z=N=sw3iI-8qelV)>yC}f9C?a)1dhr|Uk<8Cp^v+W5WcF?0bM7}SDiGCjM{a}lPvtT z!|Db=)0V|=?aZChA?&MZO$z$Sw6Dk2=zuP);g|Ot?MuEA5gL6(R^MBn3=CZ@zIW;~ zZ#?B_ZhQqt%K%RTtB`LkKVMiRAvFXNXu5qHO9`VyaBp8s_mmCT$POhVAR;Yz=;b*l zuzqeFzSp*^awqB4IuQcAxm-vYTD0b64SheA=Sr+8xf@)>#FT^^=QnMjt`}t&kXDtC6UnIaa|v6jA1> z&FJ@%-3#>Y$Tbd@3WzZv5J4dzWQcn=?mzj0EkbMDNRnrp0)ie8EvpT-vdoOH4I{xV zyZPRB{tM|4cXP6Sw>(0CSv8*ccxb;bi;M%qHCWt;;cJ<7g6B_mxX2=?&3sAQu@dHI zce3)YjgIR8>d58?ok9Qeg#ec%kPwLaPWe`#T$2lo*K>6V}F*2YsiWF zve6hp4}M*=OpB*+w39v;T1YmoB!lJ<(GUNBinxOlMIR{XBDNxp4=%zVTb|`QZHX3Db*@-@RN(R*z^OQrC+}a@YWrw+9*Sn`=kS!bU z7$7!2Tp5M~*ELKzK3dE+&aLpmy>gpy{+#S|lo$FqntL)QjeB+ga!n^iQynwotMNL6k><4%3U^fS=+84!PUdOl8pI|J_+qkHxXp$y36}vB#t>jdw4Eu zZnJ+N+;oW|uu@fUXIe()U}E7Z(LOU;H499WSSUv$2Cbb)^=sMIK3$f^R1*XUVcsE77Tz*+PrDE z^S0HXmDm2(XCdw+8Kjt?2ncc9w&Pp^g>Ac})1{ zYtU!(4eY>*hg<^!R8r_9`u{441iO!-Q8aqimQ-#h30&(0y@$)P??HOf`9+1V;#-hm zC!Xys0zGSo%KxkJKXvzQL6E&wP%X_wP3(O)pHx7TqL@-4awhP2#O`-R-_Z|LP!+&# z6zUs#C@s-d#WO{$?! zr})xLbT(?;xW~&CIJ()#>$KlXcydA4S%js)#sZ$k1lHm2zDjAYSIcV0cU_>t)* z@D7sDa0fH{$%Wyb(83dI>!aYV3}&GwP@lsy^b$4^rXLF=&hgfx`6W|Al@t`WsPlZK zt#JNHNtOZzx1LGc3Tqp{uN9*PqOoUz|qji0MnKImat0=ngw`o%BKvIcQj0>o{f% z{V5K=mxLNGte`qh`hO0RKt%#rcVdN`v+;M;7Yv8^!t{NKhYAir-1b-=Vx?U0PCNIQ z8JwRGrAIXVX)Z5V0U4#MhXe{^+u)_$%hy?aD9~5VwJ-w}X(p(>y5Ho!iM2)nvY6nJ zvc?Q~C;|2uG@5Hezd{S zVQ8Hv(!bke7amoEUu^71yr%$he`4{{_n~#XGRR@z{^sC0(hujSp?MQA2V0pfooxcc zv2Em)7iN<5*qPpCr>Sv8<<~i;mta>s-(O1(OaISuz?J*ue9*9*@H69|K>}i1|5V*N z(#vP7<#3s=iCt&Mh+zM0wT|~FLQUr9oU-8ISw@czk9c~+{-Q;r!BU{tB%15w7AQc` zq7du0L0h8t+MPvk_usmrcSLZ{@UCTxYSxLPH3D#Fzx}DgP)Dc=i|n2PBCGG%;X_`B zh@2`K#JL_yyaJj_M0CL)>HmiK6w%;K^Orf?7i~yUVwO0afj3p(Y?S0Wkla}bkWRm+ zB?@jBa|Xg- zQWWQLb_9o-VZeG;;HQSL{C{;twb8)*r_g?#0$l}2z<^buQ!ov8?`RGOlmbgC>8!lO z&fDT>0Ta>#&TZ8J{aG1Edp6x0S~L0=^U7j4O+=-0B*1)MhE8EVbT!Z*?&V>P62x;Z=YUFg6~{cq>U-x>$j^XLbepQabvPF2t6a{QP*wsL< zFpMxE{rbar0{Zh_xHV6KFA7b$aUN5Rh7fs62W`MT2V%PUX0TBug57==2 zQ2;g*-0fso`@v_92I;Xzo<-sS18^eK{}f6xf@~RBoF~+UOS%SX5*;{%zwIO6wo`{aHvVU4*1=c0PVy6MKCVZi-+6O z5uG@C^*qp(E?pJ{$K|HRPF)!GD`Nm_?R8JS&tHRX9lD?oBzS!8YzcG$72FFeM{pd) zUL4%Myq^f*2aCf9pl&6XCFo)r#8i03+;ED*){G0{{ZxZUzIg!r=b!uj!Ql^coTX_3st$|5t$m z011G8A5X8-1bXH)0l@t%0N9)SpBY;jNy&DDzK#0|12-T z5G?Qn^m41LIE)ejMshRo0Ov-*PyIwQ0_YmqMqb2_Bm(urZP*M#mjQTu?qUgaZ2@pE zj5YvZ;p@*x0BCm<20>tz5Uk6Z%Ygc~KF0x2VY%#?7Op6xa~$YOjz@ZPB%m0e-n_IE z$EjNmo`yPqQ5dQs!n(7;MNqG`3+nfmD&Xnu3IlX1xId~L%9(X&?GKkH5ukQ5qg@>U zh5ET-UmR+3#qn>f>{0*&8Ff*BdTK}0Y=pwD%bh+5UCGPgyT8ca*~H|Y6VT`?QCQdg z>~H=J%R|FiVzj~Q$@P=^{#*dt8}*^ z092eaYapZUErNg*zbDz_@>vCxu@>NEmQU7tWzb(E`&U$#UnXvD^2L)pA@ty%RC~uy zf>mV!8=`wlf;lUl-)SuIXoA)n0Of_cvc>4(B5Z=);D#w(f`2at1=FvF+j4#H7{CKX z50B6u=X8^pzmD)eCG-f{6*!{ev<*~^%OAI!=>&Qxpt)zFyFbJ>zjFbrurQrVziuxs zRnI&1i0>&G#ostqSw~sSane!yUA08{dp_Wwk)5BPNp>4E!omewjg6oDM?3YtavKaU zjCbMUf%98`^_^)R_xCy_QmeW5%vIFbJuw#d-3HcN2#W*RzhPlPf9#$ z;>ID{F(b_Da^;1MGn&mijCwD_qsbR$Rf%dcf{yh|ZiU#_l9j@)l7#e|M3YX?zYO~o zyKeI`Tz^>4uOcwcyUbywy;plG2+WMOkr9AN;W+ z$mM^%xAQB5&eP|+Of#LVL6tS|t?a%Ob`wvZ>~W%yP4P1C?yrLUX41@L<8=WT;3~vs-^gizN`TTrOuyA-)$>gLx zwz^{Z@TV!;62B7?(+|SHDIr~a#Y_Y@BbbB>1EmuGh8e5@M;AeI`Yj!EL`7&MoOx}a z6Hg*`B4Rdn{!o%6wBGy>#E7Kx#xG!sB+cDfTPxphFU$OSFMO=uGTMnE6(U<#or7sh z;AjK150_k~xFe^7^Z3fli<$AY=qZO6vkC$8o+7kc1AhaGCkPJ%!=~1T2c5{kDP4Tw z`*Fi;89zc?)L~uhkTRr@$9D_-8i!KG@nMj9^FFpd%Zo@ALeC4PU$(qdc;RXxC3fM$=vmw`5{wF>RE?WOdWqw$bHh+lLd&$$J`~QZNg!CF(^2Eh; zw48~HX0GO0k1W`DG8@yI{e$~BIuY>waJjRpf2Y>mGi>ytW${Dp0x7+sV*bss+5#n? znGwBGvh++%8Fv2O5lXK`iSHn{U;BL||NCNfrCwqrI<-Kty&QZ$4arUWa{1YO$B0<( zC4%3`%S|CKq<2m(@baUWc5#zsQ-1d(qRi}pwbCU0%8M5Z!R9)UA{l)wIz^Ga6WTSG zH0;KX)$E+{He5>M$7~JU=`$?U%KUBgQ$b5pzaU3^q}&cS|KZ_Wse7Zv54_SWVpA#` zoLl%9yA|9elyEO|?A`HvKGS;yPZvRaw=-JIoNrf*HSS_iakE6v->>JEjOne}HyUF2 zNoU|j&sad$j+-kV6>Z5mr5C)Q7>*1N{8!`2XA?xeTE#zE9_0Y_LUGRB{vH%6sqw$% zfU4`!czhb_g{+X(}>2P*2@qB?m+ zSI_P1Cc6E3-r_Xqyla5>Xz{Dyw=@_W550)Az8&Wlzx%iIH7@|GgQ?XB)uKR>aB$nq zkl^=vI84${81an(sSrBZ{igoRSnDgS;ffGAqG7_3b3dk2BbR$Lmva1}UP#qxKB=8Z z!ri{SQA428KOs}61zXb8InP?0yNQogM*CJJ2<5!Xchf8^ig&{jrsiwrYNwo^M50F) zz8@GvBIls?(o9m(VyuJ+F8P9ihTuj2Ol+MYd>qCO3kFnqA~Y%~f4>HEr)EwY_G6jk z%?sb#3QH$_U7x%$j;W9!;j;X;Xb3W=c*3(sPfAUa$&P5M?zthMy8_ ze7PEmkAH|E9h*lki{mK$ie3DIreO)&pWYv6SJF%c$Ck5UIe+pG5$%zrXdE-zg(FM{@j`GM9zs@R^eZ5 zv*vBL!vw?-^Xb}JWecvwK=4(Cc4ntf-`VQ+L z5d+7Ej#x{FZJ+UzxfP+l0d=(!8iv_2tc}_4-Zj%4$NzLZjFUaq^RcX07*!R-_FFG| z*lLVQejysdTeSSWaPFfHCWqt9D|XrFK4&9RA*kC;AP>!4B;g(w_m^cOjF&}X>*ar5 zyy(P}4gq7?YE?sTRyN@gl+F`y$0Iy?aPfg|MbLdvea(P?3!G z^qdcOmBMbn>KZICfcyT42!-6(Zzzn@eEg=wxm-&Sd32GJyzvse)~=6eXx6X@Dg8PZ zBg`=Q89e&gHwqgxScA1M!?)$a6=f|~joo2oZ)~$tq zU5|%$2*)f`;OcRC6W+IO_PD(?E;u>_chBe94G77y3-I(0{2uRWd$nE1nmTxesd%zt z*HwXET79$^4PcK;KdtK5xcN(?g2MW{ExGlnp?Q=p8I|PmJ46<u@Bu=;YO?7Mwj{x~rTZCfXZn*j^ zJC>)joB+9xX<2I)>=JND`(RR;pvKo?$>ESr+O}DpiOLa$9kMS7>LWA0zRy{8*oTGBmkCtJ7Vcg@6@;YA$_Cu+);vNz*loej@5xka|JZ2WYe0W^)_{3c(#+0O8-+w0fW zJp6SGJ97Dh%-Ga-yp^jpuXns?Rb^Tk@p17ew@{qJIMUUPbI-tT|0WH_jrdM4_cvlUS3|1PhKf6>C&raUKnu(|s z&c)UAsZ85i1ZLC(dGSGFnHjqI|Lr#8szl_7-T0t%4bZAJ*s{4)wW?&u7HSA8C2>JbLGo`GY|V6fEdo z3^wDLb82a%sgJe!mS&T)(lCj`O(nt1B8#06_FapUEpzFzv&|tf#Z&o6W+W| zzDWU>d}8xY>J`$bsOxC?r5C3oP;ME&`OR-zyiN1%Ia>O>?Uyjc)?I{CLYAWP*U-6^ zV=Lu3QmO(RJ#`PKq|RtC5umb6cNl5iGxn)mUy0=~-K%1x()GvC`?M`LY03MZz=d36z9y*yqoWTr>8Xtj9RLYv9#lK;;? z8pPp}Znp3$_lN;hz%5%yZd=YT-?F_w8s@xjrHIp;43KX^`iB4geq&B{k6xiMC0ae% zQ|7Tj2vv(jUrbfIe5><~fcjI)!_!=IEoP-Nq+cc72oG~o&>?($g5o7K zc_S?zb|&CM)BawN%JdgLZb;w|Gtbs(&PxZ+mmjnbK0zFb?<@o z$0d?EJe|xarM>xL3GRL**#(hMvKf-R#HD?iwF3Lg*WFpI@7TrLelBkZfkqN%Zwcld`y( z>b&=o_O+teHYGL44Igt87oxreQ3&@5%%aV_lz<5pd(Y}N?aavY# z+d0HFXA7oGjsh!@Tz^23W%%{?-_43Y#QnY!b}3(;uP)##e_3ofGBLLHD1uIgb27Yc zg@=bdzZQB@d30Rj+bHd{jS!^C;i`U8WnFeqEmrxtD!S*yO?dCZyw*DZXF@~JwUOve zUDEZ+>i2Ej4WxY2FSD*$*q;vXhZB8X(~=P9N*+i%Pd}4bS9E~fuGr2W+cn4huk}|8 z)^y*EKV)(YSpA()gR3{s%Nq+XxX8a9qU<%PH6#P>E_&3DuQ^+5VoK~`UDtm#o^3&O zG>2m)+*i)P67EEM+v03RuBi%&XcMKwoDVg^QXZrv;m=T3WC6c*c zDm|A5f0UaST&tLUsRgg!rzi+;pd*e8KhNoTYkXYwUL~<#1?pc>>uWdu*dW_u z*WIyxDUAxXYCP-lbCZ(b9zfQANDJPaz&K7Pqg7G@_c>axtTTenUPA|P=I^#pN%V7~ zOuO2`=EWeB0wW+jAi8d99i$Y{HiptXs)yTln#5^i%_a}zGE&xMbK4z9pi z^Ln?0lJI(0CwAe@GxvGY?0MGnW(Jwek_zu|3JxTRq53qILvu_1PP)UPyjofpl|q1n z61dLBRjOM_du^$^Ia{3_d}rYHlM&{$M$WX}>^_M5cSgI{S+9o#jT=c~{zB&$8}`hK z)RXeku)FO8=b4F6X{d)(YE zpyw|pThFh8xHIH|Q_APp$gi;_|CmnAvHOSBAiPze$~)5jndYU#ek*~XQNp1Eq%Dv5 zGrj+X3RaiLmi;4U75@wyY6)rZp0I3ldpxl`sf_{YK_Kg{CfzJrz#2E?5E0b=dg#Mf zDN5JpMDTgeoCTaVYhaG)x7~F1AE>`et*=eXJvkm2ZiL7BY9!j|pITj%xTaUiu}e*s56i^q(P!f{2H&;7mOi@?LM0MV)xR@TxYG*G6@J1(_w=koAkHokr zF%zSEybEIhdLu$pr3n9!{rVS5_mbaqcLld4f4mqtAoV4uRib_IXkbZNTga;s?|=d_ zuzqN2zDe}S6X7256Pe{+u`Js&9xq59Yu>7wQD1$Y$DI)sl+9o#?#1(GgohTRcH!WQ zs@PtVzD>ke&gExXWQ8ze`uzQnqOLXFUB&-UJf|jj)tf2PXQslj?8Od^+G&mceb_tO z)d=)=tWE#8-Pk(3FT8x}{Z4r?i|t+&4HYaMEb?70rY=2Qj(JMiw z{V@88L-kopWoPuowoLD-V3zbVDO(Js22F-HSiCP;oJ|M{(a6gbwATeqJ>GLst#G~b z^%>rTi<=S!2aW1tThhpyB)r1&iuG)s@i%9G{CWboTTtx|8h2R*I%%tA6~>DQDs9FK zW>*1gUnnCt-sb?-eP20uzYz8=EC#@Q(8`R7=hYFJ zx@;l>e^!eLJBIBUyz+VAgsW2R9}V%^QRzT3u@cap?!&%a1BeI&y3 zDd+lR8Igc9Yy8x3I{CxW%JUs*_cd#~G*5hrJTp3$N|SIK{lEWcVJaM;h=d-vW20vZ P0B~TR#op}QjIjR)wK5d} literal 0 HcmV?d00001 diff --git a/android/build.gradle b/android/build.gradle index 4a5e8b71dc..8e7f728f98 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -39,7 +39,24 @@ ext { RELEASE_TYPE = project.hasProperty('RELEASE_TYPE') ? project.getProperty('RELEASE_TYPE') : 'DEV' BUILD_BRANCH = project.hasProperty('BUILD_BRANCH') ? project.getProperty('BUILD_BRANCH') : '' EXEC_SUFFIX = Os.isFamily(Os.FAMILY_WINDOWS) ? '.exe' : '' - QT5_DEPS = [ 'Qt5Core', 'Qt5Gui', 'Qt5Network', 'Qt5Qml', 'Qt5Quick', 'Qt5Script', 'Qt5Widgets', 'Qt5OpenGL' ] + QT5_DEPS = [ + 'Qt5Core', + 'Qt5Gui', + 'Qt5Multimedia', + 'Qt5Network', + 'Qt5OpenGL', + 'Qt5Qml', + 'Qt5Quick', + 'Qt5Script', + 'Qt5ScriptTools', + 'Qt5WebChannel', + 'Qt5WebSockets', + 'Qt5Widgets', + 'Qt5XmlPatterns', + // Android specific + 'Qt5AndroidExtras', + 'Qt5WebView', + ] } def baseFolder = new File(HIFI_ANDROID_PRECOMPILED) @@ -47,11 +64,11 @@ def appDir = new File(projectDir, 'app') def jniFolder = new File(appDir, 'src/main/jniLibs/arm64-v8a') def baseUrl = 'https://hifi-public.s3.amazonaws.com/austin/android/' -def qtFile='qt-5.9.3_linux_armv8-libcpp.tgz' -def qtChecksum='547da3547d5690144e23d6504c6d6e91' +def qtFile='qt-5.9.3_linux_armv8-libcpp_openssl.tgz' +def qtChecksum='04599670ccca84bd2b15f6915568eb2d' if (Os.isFamily(Os.FAMILY_MAC)) { - qtFile = 'qt-5.9.3_osx_armv8-libcpp.tgz' - qtChecksum='6fa3e068cfdee863fc909b294a3a0cc6' + qtFile = 'qt-5.9.3_osx_armv8-libcpp_openssl.tgz' + qtChecksum='4b02de9d67d6bfb202355a808d2d9c59' } else if (Os.isFamily(Os.FAMILY_WINDOWS)) { qtFile = 'qt-5.9.3_win_armv8-libcpp_openssl.tgz' qtChecksum='a93d22c0c59aa112fda18c4c6d157d17' @@ -146,6 +163,7 @@ def scanQmlImports = { File qmlRootPath -> " -importPath ${qmlRoot.absolutePath}/qml" def commandResult = captureOutput(command) + println commandResult new JsonSlurper().parseText(commandResult).each { if (!it.containsKey('path')) { println "Warning: QML import could not be resolved in any of the import paths: ${it.name}" @@ -358,7 +376,8 @@ task extractGvrBinaries(dependsOn: extractDependencies) { task qtBundle { doLast { parseQtDependencies(QT5_DEPS) - scanQmlImports(new File("${appDir}/../../interface/resources/qml/")) + //scanQmlImports(new File("${appDir}/../../interface/resources/qml/")) + scanQmlImports(new File("${projectDir}/app/src/main/cpp")) def libDestinationDirectory = jniFolder def jarDestinationDirectory = new File(appDir, 'libs') diff --git a/android/build_recipes.md b/android/build_recipes.md index 3bd4310a25..78ca961f5c 100644 --- a/android/build_recipes.md +++ b/android/build_recipes.md @@ -1,3 +1,36 @@ +Different libraries require different mechanism for building. Some are easiest with the standalone toolchain. Some are easiest with the ndk-build tool. Some can rely on CMake to do the right thing. + +## Setup + +### Android build environment + +You need the Android NDK and SDK. The easiest way to get these is to download Android Studio for your platform and use the SDK manager in Studio to install the items. In particular you will need Android API levels 24 and 26, as well as the NDK, CMake, and LLDB. You should be using NDK version 16 or higher. + +The Studio installation can install the SDK wherver you like. This guide assumes you install it to `$HOME/Android/SDK`. It will install the NDK inside the SDK in a folder named `ndk-bundle` but for convenience we will assume a symlink from `$HOME/Android/NDK` to the actual NDK folder exists + +Additionally, some of the tools require a standalone toolchain in order to build. From the NDK build/tools directory you can execute the following command + +`./make-standalone-toolchain.sh --arch=arm64 --platform=android-24 --install-dir=$HOME/Android/arm64_toolchain` + +This will create the toolchain and install it in `$HOME/Android/arm64_toolchain` + +When doing a build that relies on the toolchain you can execute the following commands to enable it + +``` +target_host=aarch64-linux-android +export PATH=$PATH:$HOME/Android/arm64_toolchain/bin +export AR=$target_host-ar +export AS=$target_host-as +export CC=$target_host-gcc +export CXX=$target_host-g++ +export LD=$target_host-ld +export STRIP=$target_host-strip +export CFLAGS="-fPIE -fPIC" +export LDFLAGS="-pie" +``` + + + ## Qt ### Windows host @@ -15,6 +48,10 @@ * python * gmake * If any of them fail, fix your path and restart the bash prompt +* Fetch the pre-built OpenSSL binaries for Android/iOS from here: https://github.com/leenjewel/openssl_for_ios_and_android/releases + * Grab the latest release of the 1.0.2 series + * Open the archive and extract the `/android/openssl-arm64-v8a` folder + * Download the Qt sources * `git clone git://code.qt.io/qt/qt5.git` * `cd qt5` @@ -23,5 +60,28 @@ * `git submodule update --recursive` * `cd ..` * Create a build directory with the command `mkdir qt5build` -* Configure the Qt5 build with the command `../qt5/configure -xplatform android-clang -android-ndk-host windows-x86_64 -confirm-license -opensource --disable-rpath -nomake tests -nomake examples -skip qttranslations -skip qtserialport -skip qt3d -skip qtwebengine -skip qtlocation -skip qtwayland -skip qtsensors -skip qtgamepad -skip qtgamepad -skip qtspeech -skip qtcharts -skip qtx11extras -skip qtmacextras -skip qtvirtualkeyboard -skip qtpurchasing -skip qtdatavis3d -android-ndk C:/Android/NDK -android-toolchain-version 4.9 -android-arch arm64-v8a -no-warnings-are-errors -android-ndk-platform android-24 -v -platform win32-g++ -prefix C:/qt5build_debug -android-sdk C:/Android/SDK ` - \ No newline at end of file +* Configure the Qt5 build with the command `../qt5/configure -xplatform android-clang -android-ndk-host windows-x86_64 -confirm-license -opensource --disable-rpath -nomake tests -nomake examples -skip qttranslations -skip qtserialport -skip qt3d -skip qtwebengine -skip qtlocation -skip qtwayland -skip qtsensors -skip qtgamepad -skip qtgamepad -skip qtspeech -skip qtcharts -skip qtx11extras -skip qtmacextras -skip qtvirtualkeyboard -skip qtpurchasing -skip qtdatavis3d -android-ndk C:/Android/NDK -android-toolchain-version 4.9 -android-arch arm64-v8a -no-warnings-are-errors -android-ndk-platform android-24 -v -platform win32-g++ -prefix C:/qt5build_debug -android-sdk C:/Android/SDK -c++std c++14 -openssl-linked -L/lib -I/include` + + + +## TBB + +Use the ndk-build tool + +ndk-build tbb tbbmalloc target=android arch=ia32 tbb_os=windows ndk_version=16 + +## OpenSSL + +Use a standalone toolchain + +* Grab the latest 1.1.0x series source from https://github.com/openssl/openssl/releases +* Follow the NDK guidelines for building a standalone toolchain for aarch64 +* Use the following script to configure and build OpenSSL +* Enable the standalone toolchain with the export commands described above +* Configure SSL with the command `./Configure android64-aarch64 no-asm no-ssl2 no-ssl3 no-comp no-hw no-engine --prefix=$HOME/Android/openssl_1.1.0g` +* Build and install SSL with the command `make depend && make && make install` + + + + + diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 4c1b8d8d92..a38d428eba 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -56,14 +56,6 @@ else () list(REMOVE_ITEM INTERFACE_SRCS ${SPEECHRECOGNIZER_CPP}) endif () -if (ANDROID) - set(PLATFORM_QT_COMPONENTS AndroidExtras) - set(PLATFORM_QT_LIBRARIES Qt5::AndroidExtras) -else () - set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets) - set(PLATFORM_QT_LIBRARIES Qt5::WebEngine Qt5::WebEngineWidgets) -endif () - find_package( Qt5 COMPONENTS Gui Multimedia Network OpenGL Qml Quick Script Svg diff --git a/libraries/gl/src/gl/Config.h b/libraries/gl/src/gl/Config.h index ff282a1ca0..b1bafe1ba6 100644 --- a/libraries/gl/src/gl/Config.h +++ b/libraries/gl/src/gl/Config.h @@ -14,10 +14,10 @@ #include -#if defined(QT_OPENGL_ES_3_1) -// Minimum GL ES version required is 3.1 +#if defined(Q_OS_ANDROID) +// Minimum GL ES version required is 3.2 #define GL_MIN_VERSION_MAJOR 0x03 -#define GL_MIN_VERSION_MINOR 0x01 +#define GL_MIN_VERSION_MINOR 0x02 #define GL_DEFAULT_VERSION_MAJOR GL_MIN_VERSION_MAJOR #define GL_DEFAULT_VERSION_MINOR GL_MIN_VERSION_MINOR #else @@ -33,7 +33,7 @@ #if defined(Q_OS_ANDROID) #include -#include +#include #define GL_DEPTH_COMPONENT32_OES 0x81A7 #define GL_TIME_ELAPSED_EXT 0x88BF diff --git a/libraries/gl/src/gl/GLHelpers.cpp b/libraries/gl/src/gl/GLHelpers.cpp index ed0594135a..0e3321d99d 100644 --- a/libraries/gl/src/gl/GLHelpers.cpp +++ b/libraries/gl/src/gl/GLHelpers.cpp @@ -28,7 +28,7 @@ const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() { static QSurfaceFormat format; static std::once_flag once; std::call_once(once, [] { -#if defined(QT_OPENGL_ES_3_1) +#if defined(Q_OS_ANDROID) format.setRenderableType(QSurfaceFormat::OpenGLES); format.setRedBufferSize(8); format.setGreenBufferSize(8); diff --git a/libraries/gl/src/gl/GLHelpers.h b/libraries/gl/src/gl/GLHelpers.h index 80fc2c5f70..73319e2e6d 100644 --- a/libraries/gl/src/gl/GLHelpers.h +++ b/libraries/gl/src/gl/GLHelpers.h @@ -25,8 +25,9 @@ class QSurfaceFormat; class QGLFormat; template -#if defined(QT_OPENGL_ES_3_1) -void setGLFormatVersion(F& format, int major = 3, int minor = 1) +// https://bugreports.qt.io/browse/QTBUG-64703 prevents us from using "defined(QT_OPENGL_ES_3_1)" +#if defined(Q_OS_ANDROID) +void setGLFormatVersion(F& format, int major = 3, int minor = 2) #else void setGLFormatVersion(F& format, int major = 4, int minor = 5) #endif diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.cpp b/libraries/gl/src/gl/OffscreenGLCanvas.cpp index b974564705..eb99933101 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.cpp +++ b/libraries/gl/src/gl/OffscreenGLCanvas.cpp @@ -46,15 +46,28 @@ bool OffscreenGLCanvas::create(QOpenGLContext* sharedContext) { _context->setShareContext(sharedContext); } _context->setFormat(getDefaultOpenGLSurfaceFormat()); - - if (_context->create()) { - _offscreenSurface->setFormat(_context->format()); - _offscreenSurface->create(); - return _offscreenSurface->isValid(); + if (!_context->create()) { + qFatal("Failed to create OffscreenGLCanvas context"); } - qWarning("Failed to create OffscreenGLCanvas context"); - return false; + _offscreenSurface->setFormat(_context->format()); + _offscreenSurface->create(); +#if !defined(Q_OS_ANDROID) + if (!_context->makeCurrent(_offscreenSurface)) { + qFatal("Unable to make offscreen surface current"); + } +#else + // For some reason, the offscreen surface is considered invalid on android + // possibly because of a bad format? Would need to add some logging to the + // eglpbuffer implementation used from the android platform plugin. + // Alternatively investigate the use of an invisible surface view to do + // a 'native' offscreen surface + if (!_offscreenSurface->isValid()) { + qFatal("Offscreen surface is invalid"); + } +#endif + + return true; } bool OffscreenGLCanvas::makeCurrent() { diff --git a/libraries/plugins/src/plugins/PluginManager.cpp b/libraries/plugins/src/plugins/PluginManager.cpp index 18ac905ef1..630520957a 100644 --- a/libraries/plugins/src/plugins/PluginManager.cpp +++ b/libraries/plugins/src/plugins/PluginManager.cpp @@ -177,10 +177,6 @@ const SteamClientPluginPointer PluginManager::getSteamClientPlugin() { return steamClientPlugin; } -#ifndef Q_OS_ANDROID - -static DisplayPluginList displayPlugins; - const DisplayPluginList& PluginManager::getDisplayPlugins() { static std::once_flag once; static auto deviceAddedCallback = [](QString deviceName) { @@ -194,7 +190,7 @@ const DisplayPluginList& PluginManager::getDisplayPlugins() { std::call_once(once, [&] { // Grab the built in plugins - displayPlugins = _displayPluginProvider(); + _displayPlugins = _displayPluginProvider(); // Now grab the dynamic plugins @@ -202,11 +198,11 @@ const DisplayPluginList& PluginManager::getDisplayPlugins() { DisplayProvider* displayProvider = qobject_cast(loader->instance()); if (displayProvider) { for (auto displayPlugin : displayProvider->getDisplayPlugins()) { - displayPlugins.push_back(displayPlugin); + _displayPlugins.push_back(displayPlugin); } } } - for (auto plugin : displayPlugins) { + for (auto plugin : _displayPlugins) { connect(plugin.get(), &Plugin::deviceConnected, this, deviceAddedCallback, Qt::QueuedConnection); connect(plugin.get(), &Plugin::subdeviceConnected, this, subdeviceAddedCallback, Qt::QueuedConnection); plugin->setContainer(_container); @@ -214,21 +210,17 @@ const DisplayPluginList& PluginManager::getDisplayPlugins() { } }); - return displayPlugins; + return _displayPlugins; } void PluginManager::disableDisplayPlugin(const QString& name) { - for (size_t i = 0; i < displayPlugins.size(); ++i) { - if (displayPlugins[i]->getName() == name) { - displayPlugins.erase(displayPlugins.begin() + i); - break; - } - } + std::remove_if(_displayPlugins.begin(), _displayPlugins.end(), [&](const DisplayPluginPointer& plugin){ + return plugin->getName() == name; + }); } const InputPluginList& PluginManager::getInputPlugins() { - static InputPluginList inputPlugins; static std::once_flag once; static auto deviceAddedCallback = [](QString deviceName) { qCDebug(plugins) << "Added device: " << deviceName; @@ -240,7 +232,7 @@ const InputPluginList& PluginManager::getInputPlugins() { }; std::call_once(once, [&] { - inputPlugins = _inputPluginProvider(); + _inputPlugins = _inputPluginProvider(); // Now grab the dynamic plugins for (auto loader : getLoadedPlugins()) { @@ -248,20 +240,20 @@ const InputPluginList& PluginManager::getInputPlugins() { if (inputProvider) { for (auto inputPlugin : inputProvider->getInputPlugins()) { if (inputPlugin->isSupported()) { - inputPlugins.push_back(inputPlugin); + _inputPlugins.push_back(inputPlugin); } } } } - for (auto plugin : inputPlugins) { + for (auto plugin : _inputPlugins) { connect(plugin.get(), &Plugin::deviceConnected, this, deviceAddedCallback, Qt::QueuedConnection); connect(plugin.get(), &Plugin::subdeviceConnected, this, subdeviceAddedCallback, Qt::QueuedConnection); plugin->setContainer(_container); plugin->init(); } }); - return inputPlugins; + return _inputPlugins; } void PluginManager::setPreferredDisplayPlugins(const QStringList& displays) { @@ -328,4 +320,3 @@ void PluginManager::shutdown() { } } } -#endif diff --git a/libraries/plugins/src/plugins/PluginManager.h b/libraries/plugins/src/plugins/PluginManager.h index 08fe4fde20..f16ad7d09f 100644 --- a/libraries/plugins/src/plugins/PluginManager.h +++ b/libraries/plugins/src/plugins/PluginManager.h @@ -44,4 +44,6 @@ private: CodecPluginProvider _codecPluginProvider { []()->CodecPluginList { return {}; } }; InputPluginSettingsPersister _inputSettingsPersister { [](const InputPluginList& list) {} }; PluginContainer* _container { nullptr }; + DisplayPluginList _displayPlugins; + InputPluginList _inputPlugins; }; diff --git a/libraries/script-engine/src/FileScriptingInterface.cpp b/libraries/script-engine/src/FileScriptingInterface.cpp index fdae04f267..e475a2e445 100644 --- a/libraries/script-engine/src/FileScriptingInterface.cpp +++ b/libraries/script-engine/src/FileScriptingInterface.cpp @@ -9,21 +9,25 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "FileScriptingInterface.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(Q_OS_ANDROID) #include #include +#endif -#include "FileScriptingInterface.h" #include "ResourceManager.h" #include "ScriptEngineLogging.h" @@ -68,7 +72,9 @@ void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool } QStringList FileScriptingInterface::unzipFile(QString path, QString tempDir) { - +#if defined(Q_OS_ANDROID) + return QStringList(); +#else QDir dir(path); QString dirName = dir.path(); qCDebug(scriptengine) << "Directory to unzip: " << dirName; @@ -83,7 +89,7 @@ QStringList FileScriptingInterface::unzipFile(QString path, QString tempDir) { qCDebug(scriptengine) << "Extraction failed"; return list; } - +#endif } // fix to check that we are only referring to a temporary directory @@ -131,11 +137,12 @@ void FileScriptingInterface::recursiveFileScan(QFileInfo file, QString* dirName) return; }*/ QFileInfoList files; - +#if !defined(Q_OS_ANDROID) if (file.fileName().contains(".zip")) { qCDebug(scriptengine) << "Extracting archive: " + file.fileName(); JlCompress::extractDir(file.fileName()); } +#endif files = file.dir().entryInfoList(); /*if (files.empty()) { diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 6fbcd6a794..792653b75b 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -1607,14 +1607,14 @@ QVariantMap ScriptEngine::fetchModuleSource(const QString& modulePath, const boo if (!loader->isFinished()) { QTimer monitor; QEventLoop loop; - QObject::connect(loader, &BatchLoader::finished, this, [this, &monitor, &loop]{ + QObject::connect(loader, &BatchLoader::finished, this, [&monitor, &loop]{ monitor.stop(); loop.quit(); }); // this helps detect the case where stop() is invoked during the download // but not seen in time to abort processing in onload()... - connect(&monitor, &QTimer::timeout, this, [this, &loop, &loader]{ + connect(&monitor, &QTimer::timeout, this, [this, &loop]{ if (isStopping()) { loop.exit(-1); } @@ -2247,7 +2247,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co QTimer timeout; timeout.setSingleShot(true); timeout.start(SANDBOX_TIMEOUT); - connect(&timeout, &QTimer::timeout, [&sandbox, SANDBOX_TIMEOUT, scriptOrURL]{ + connect(&timeout, &QTimer::timeout, [&sandbox, scriptOrURL]{ qCDebug(scriptengine) << "ScriptEngine::entityScriptContentAvailable timeout(" << scriptOrURL << ")"; // Guard against infinite loops and non-performant code diff --git a/libraries/ui/CMakeLists.txt b/libraries/ui/CMakeLists.txt index 53006b8943..2dd23f5134 100644 --- a/libraries/ui/CMakeLists.txt +++ b/libraries/ui/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME ui) -setup_hifi_library(OpenGL Multimedia Network Qml Quick Script WebChannel WebEngine WebSockets XmlPatterns) +setup_hifi_library(OpenGL Multimedia Network Qml Quick Script WebChannel WebSockets XmlPatterns ${PLATFORM_QT_COMPONENTS}) link_hifi_libraries(shared networking gl audio audio-client plugins pointers) include_hifi_library_headers(controllers) diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 9a591018f5..536b1c6127 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -276,7 +277,9 @@ private: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8.0f); +#if !defined(Q_OS_ANDROID) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.2f); +#endif glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8.0f); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, size.x, size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); return newTexture; @@ -416,6 +419,8 @@ static size_t globalEngineRefCount{ 0 }; #endif void initializeQmlEngine(QQmlEngine* engine, QQuickWindow* window) { + new QQmlFileSelector(engine, window); + // register the pixmap image provider (used only for security image, for now) engine->addImageProvider(ImageProvider::PROVIDER_NAME, new ImageProvider()); @@ -440,8 +445,10 @@ void initializeQmlEngine(QQmlEngine* engine, QQuickWindow* window) { if (!javaScriptToInject.isEmpty()) { rootContext->setContextProperty("eventBridgeJavaScriptToInject", QVariant(javaScriptToInject)); } +#if !defined(Q_OS_ANDROID) rootContext->setContextProperty("FileTypeProfile", new FileTypeProfile(rootContext)); rootContext->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(rootContext)); +#endif rootContext->setContextProperty("Paths", DependencyManager::get().data()); } @@ -615,10 +622,12 @@ void OffscreenQmlSurface::onAboutToQuit() { } void OffscreenQmlSurface::disconnectAudioOutputTimer() { +#if !defined(Q_OS_ANDROID) if (_audioOutputUpdateTimer.isActive()) { _audioOutputUpdateTimer.stop(); } QObject::disconnect(&_audioOutputUpdateTimer); +#endif } void OffscreenQmlSurface::create() { @@ -668,7 +677,8 @@ void OffscreenQmlSurface::create() { // Find a way to flag older scripts using this mechanism and wanr that this is deprecated _qmlContext->setContextProperty("eventBridgeWrapper", new EventBridgeWrapper(this, _qmlContext)); _renderControl->initialize(_canvas->getContext()); - + +#if !defined(Q_OS_ANDROID) // Connect with the audio client and listen for audio device changes auto audioIO = DependencyManager::get(); connect(audioIO.data(), &AudioClient::deviceChanged, this, [&](QAudio::Mode mode, const QAudioDeviceInfo& device) { @@ -684,6 +694,7 @@ void OffscreenQmlSurface::create() { int waitForAudioQmlMs = 200; _audioOutputUpdateTimer.setInterval(waitForAudioQmlMs); _audioOutputUpdateTimer.setSingleShot(true); +#endif // When Quick says there is a need to render, we will not render immediately. Instead, // a timer with a small interval is used to get better performance. @@ -695,20 +706,25 @@ void OffscreenQmlSurface::create() { } void OffscreenQmlSurface::changeAudioOutputDevice(const QString& deviceName, bool isHtmlUpdate) { +#if !defined(Q_OS_ANDROID) if (_rootItem != nullptr && !isHtmlUpdate) { QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::QueuedConnection); } emit audioOutputDeviceChanged(deviceName); +#endif } void OffscreenQmlSurface::forceHtmlAudioOutputDeviceUpdate() { +#if !defined(Q_OS_ANDROID) auto audioIO = DependencyManager::get(); QString deviceName = audioIO->getActiveAudioDevice(QAudio::AudioOutput).deviceName(); QMetaObject::invokeMethod(this, "changeAudioOutputDevice", Qt::QueuedConnection, Q_ARG(QString, deviceName), Q_ARG(bool, true)); +#endif } void OffscreenQmlSurface::forceQmlAudioOutputDeviceUpdate() { +#if !defined(Q_OS_ANDROID) if (QThread::currentThread() != qApp->thread()) { QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::QueuedConnection); } else { @@ -719,6 +735,7 @@ void OffscreenQmlSurface::forceQmlAudioOutputDeviceUpdate() { } _audioOutputUpdateTimer.start(); } +#endif } static uvec2 clampSize(const uvec2& size, uint32_t maxDimension) { @@ -1348,14 +1365,11 @@ void OffscreenQmlSurface::lowerKeyboard() { void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool numeric, bool passwordField) { qCDebug(uiLogging) << "setKeyboardRaised: " << object << ", raised: " << raised << ", numeric: " << numeric << ", password: " << passwordField; -#if Q_OS_ANDROID - return; -#endif - if (!object) { return; } +#if !defined(Q_OS_ANDROID) // if HMD is being worn, allow keyboard to open. allow it to close, HMD or not. if (!raised || qApp->property(hifi::properties::HMD).toBool()) { QQuickItem* item = dynamic_cast(object); @@ -1392,6 +1406,7 @@ void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool n item = dynamic_cast(item->parentItem()); } } +#endif } void OffscreenQmlSurface::emitScriptEvent(const QVariant& message) { diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 4c23c62c12..03f7475f61 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -173,9 +173,11 @@ private: uint64_t _lastRenderTime { 0 }; uvec2 _size; +#if !defined(Q_OS_ANDROID) QTimer _audioOutputUpdateTimer; QString _currentAudioOutputDevice; - +#endif + // Texture management TextureAndFence _latestTextureAndFence { 0, 0 }; diff --git a/libraries/ui/src/ui/types/FileTypeProfile.cpp b/libraries/ui/src/ui/types/FileTypeProfile.cpp index 6fcd8df669..90a2c6ba18 100644 --- a/libraries/ui/src/ui/types/FileTypeProfile.cpp +++ b/libraries/ui/src/ui/types/FileTypeProfile.cpp @@ -13,6 +13,7 @@ #include "FileTypeRequestInterceptor.h" +#if !defined(Q_OS_ANDROID) static const QString QML_WEB_ENGINE_STORAGE_NAME = "qmlWebEngine"; FileTypeProfile::FileTypeProfile(QObject* parent) : @@ -24,3 +25,4 @@ FileTypeProfile::FileTypeProfile(QObject* parent) : auto requestInterceptor = new FileTypeRequestInterceptor(this); setRequestInterceptor(requestInterceptor); } +#endif \ No newline at end of file diff --git a/libraries/ui/src/ui/types/FileTypeProfile.h b/libraries/ui/src/ui/types/FileTypeProfile.h index f922fd66de..c7d07cd822 100644 --- a/libraries/ui/src/ui/types/FileTypeProfile.h +++ b/libraries/ui/src/ui/types/FileTypeProfile.h @@ -14,12 +14,15 @@ #ifndef hifi_FileTypeProfile_h #define hifi_FileTypeProfile_h +#include + +#if !defined(Q_OS_ANDROID) #include class FileTypeProfile : public QQuickWebEngineProfile { public: FileTypeProfile(QObject* parent = Q_NULLPTR); }; - +#endif #endif // hifi_FileTypeProfile_h diff --git a/libraries/ui/src/ui/types/FileTypeRequestInterceptor.cpp b/libraries/ui/src/ui/types/FileTypeRequestInterceptor.cpp index 91bacd46a6..25866ad395 100644 --- a/libraries/ui/src/ui/types/FileTypeRequestInterceptor.cpp +++ b/libraries/ui/src/ui/types/FileTypeRequestInterceptor.cpp @@ -15,7 +15,11 @@ #include "RequestFilters.h" +#if !defined(Q_OS_ANDROID) + void FileTypeRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) { RequestFilters::interceptHFWebEngineRequest(info); RequestFilters::interceptFileType(info); } + +#endif \ No newline at end of file diff --git a/libraries/ui/src/ui/types/FileTypeRequestInterceptor.h b/libraries/ui/src/ui/types/FileTypeRequestInterceptor.h index be971daf7a..b8a01a53fa 100644 --- a/libraries/ui/src/ui/types/FileTypeRequestInterceptor.h +++ b/libraries/ui/src/ui/types/FileTypeRequestInterceptor.h @@ -14,6 +14,9 @@ #ifndef hifi_FileTypeRequestInterceptor_h #define hifi_FileTypeRequestInterceptor_h +#include + +#if !defined(Q_OS_ANDROID) #include class FileTypeRequestInterceptor : public QWebEngineUrlRequestInterceptor { @@ -22,5 +25,6 @@ public: virtual void interceptRequest(QWebEngineUrlRequestInfo& info) override; }; +#endif #endif // hifi_FileTypeRequestInterceptor_h diff --git a/libraries/ui/src/ui/types/HFWebEngineProfile.cpp b/libraries/ui/src/ui/types/HFWebEngineProfile.cpp index 685af45dad..381bdb10bd 100644 --- a/libraries/ui/src/ui/types/HFWebEngineProfile.cpp +++ b/libraries/ui/src/ui/types/HFWebEngineProfile.cpp @@ -13,6 +13,8 @@ #include "HFWebEngineRequestInterceptor.h" +#if !defined(Q_OS_ANDROID) + static const QString QML_WEB_ENGINE_STORAGE_NAME = "qmlWebEngine"; HFWebEngineProfile::HFWebEngineProfile(QObject* parent) : @@ -24,3 +26,5 @@ HFWebEngineProfile::HFWebEngineProfile(QObject* parent) : auto requestInterceptor = new HFWebEngineRequestInterceptor(this); setRequestInterceptor(requestInterceptor); } + +#endif \ No newline at end of file diff --git a/libraries/ui/src/ui/types/HFWebEngineProfile.h b/libraries/ui/src/ui/types/HFWebEngineProfile.h index 5c7655479e..30da489c92 100644 --- a/libraries/ui/src/ui/types/HFWebEngineProfile.h +++ b/libraries/ui/src/ui/types/HFWebEngineProfile.h @@ -14,12 +14,15 @@ #ifndef hifi_HFWebEngineProfile_h #define hifi_HFWebEngineProfile_h +#include + +#if !defined(Q_OS_ANDROID) #include class HFWebEngineProfile : public QQuickWebEngineProfile { public: HFWebEngineProfile(QObject* parent = Q_NULLPTR); }; - +#endif #endif // hifi_HFWebEngineProfile_h diff --git a/libraries/ui/src/ui/types/HFWebEngineRequestInterceptor.cpp b/libraries/ui/src/ui/types/HFWebEngineRequestInterceptor.cpp index eaf0de7245..5a11c32efa 100644 --- a/libraries/ui/src/ui/types/HFWebEngineRequestInterceptor.cpp +++ b/libraries/ui/src/ui/types/HFWebEngineRequestInterceptor.cpp @@ -16,6 +16,10 @@ #include "AccountManager.h" #include "RequestFilters.h" +#if !defined(Q_OS_ANDROID) + void HFWebEngineRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) { RequestFilters::interceptHFWebEngineRequest(info); } + +#endif \ No newline at end of file diff --git a/libraries/ui/src/ui/types/HFWebEngineRequestInterceptor.h b/libraries/ui/src/ui/types/HFWebEngineRequestInterceptor.h index a4c308426c..b5521a106e 100644 --- a/libraries/ui/src/ui/types/HFWebEngineRequestInterceptor.h +++ b/libraries/ui/src/ui/types/HFWebEngineRequestInterceptor.h @@ -14,6 +14,9 @@ #ifndef hifi_HFWebEngineRequestInterceptor_h #define hifi_HFWebEngineRequestInterceptor_h +#include + +#if !defined(Q_OS_ANDROID) #include class HFWebEngineRequestInterceptor : public QWebEngineUrlRequestInterceptor { @@ -22,5 +25,6 @@ public: virtual void interceptRequest(QWebEngineUrlRequestInfo& info) override; }; +#endif #endif // hifi_HFWebEngineRequestInterceptor_h diff --git a/libraries/ui/src/ui/types/RequestFilters.cpp b/libraries/ui/src/ui/types/RequestFilters.cpp index 0a0e67756d..12e143a726 100644 --- a/libraries/ui/src/ui/types/RequestFilters.cpp +++ b/libraries/ui/src/ui/types/RequestFilters.cpp @@ -17,6 +17,8 @@ #include "AccountManager.h" +#if !defined(Q_OS_ANDROID) + namespace { bool isAuthableHighFidelityURL(const QUrl& url) { @@ -77,3 +79,4 @@ void RequestFilters::interceptFileType(QWebEngineUrlRequestInfo& info) { info.setHttpHeader(CONTENT_HEADER.toLocal8Bit(), TYPE_VALUE.toLocal8Bit()); } } +#endif \ No newline at end of file diff --git a/libraries/ui/src/ui/types/RequestFilters.h b/libraries/ui/src/ui/types/RequestFilters.h index 0d7d66e155..ccab6a6ee3 100644 --- a/libraries/ui/src/ui/types/RequestFilters.h +++ b/libraries/ui/src/ui/types/RequestFilters.h @@ -14,15 +14,17 @@ #ifndef hifi_RequestFilters_h #define hifi_RequestFilters_h +#include + +#if !defined(Q_OS_ANDROID) #include #include class RequestFilters : public QObject { - Q_OBJECT - -public: +public: static void interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info); static void interceptFileType(QWebEngineUrlRequestInfo& info); }; +#endif #endif // hifi_RequestFilters_h