diff --git a/Projects/Android/AndroidManifest.xml b/Projects/Android/AndroidManifest.xml index 614da97..da5e543 100644 --- a/Projects/Android/AndroidManifest.xml +++ b/Projects/Android/AndroidManifest.xml @@ -25,12 +25,14 @@ + + + diff --git a/Projects/Android/build.gradle b/Projects/Android/build.gradle index b9e1731..07a5f94 100644 --- a/Projects/Android/build.gradle +++ b/Projects/Android/build.gradle @@ -1,7 +1,20 @@ +buildscript { + repositories { + google() // For Gradle 4.0+ + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:8.2.1' + } +} + apply plugin: 'com.android.application' -apply from: "${rootProject.projectDir}/XrApp.gradle" android { + + namespace = "com.drbeef.quakequest" + // This is the name of the generated apk file, which will have // -debug.apk or -release.apk appended to it. // The filename doesn't effect the Android installation process. @@ -15,19 +28,82 @@ android { applicationId "com.drbeef." + project.archivesBaseName // override app plugin abiFilters for both 32 and 64-bit support - externalNativeBuild { - ndk { - abiFilters 'arm64-v8a' - } - ndkBuild { - abiFilters 'arm64-v8a' - } - } + externalNativeBuild { + ndk { + abiFilters 'arm64-v8a' + } + ndkBuild { + abiFilters 'arm64-v8a' + } + } - minSdkVersion 26 - targetSdkVersion 26 + minSdkVersion 32 + targetSdkVersion 32 } + externalNativeBuild { + ndkBuild { + path file('jni/Android.mk') + } + } + + signingConfigs { + def keystorePath = (project.hasProperty('key.store')) ? + new File(project.getProperty('key.store')) : + project.file('android.debug.keystore') + + def keystorePassword = (project.hasProperty('key.store.password')) ? + project.getProperty('key.store.password') : 'android' + + def keystoreKeyAlias = (project.hasProperty('key.alias')) ? + project.getProperty('key.alias') : 'androiddebugkey' + + def keystoreKeyPassword = (project.hasProperty('key.alias.password')) ? + project.getProperty('key.alias.password') : 'android' + + debug { + storeFile keystorePath + storePassword keystorePassword + keyAlias keystoreKeyAlias + keyPassword keystoreKeyPassword + v2SigningEnabled true + } + + release { + storeFile keystorePath + storePassword keystorePassword + keyAlias keystoreKeyAlias + keyPassword keystoreKeyPassword + v2SigningEnabled true + } + } + + buildTypes { + debug { + signingConfig signingConfigs.debug + debuggable true + jniDebuggable true + + externalNativeBuild { + ndkBuild { + arguments "NDK_DEBUG=1","USE_ASAN=1" + } + } + } + + release { + signingConfig signingConfigs.release + debuggable false + jniDebuggable false + + externalNativeBuild { + ndkBuild { + arguments "NDK_DEBUG=0","USE_ASAN=0" + } + } + } + } + sourceSets { main { manifest.srcFile 'AndroidManifest.xml' @@ -42,25 +118,40 @@ android { targetCompatibility = '1.8' } + lintOptions { + checkReleaseBuilds false + disable 'ExpiredTargetSdkVersion' + } + packagingOptions { exclude 'lib/arm64-v8a/libopenxr_loader.so' } + compileSdkVersion = 32 - compileSdkVersion = 26 - buildToolsVersion = '29.0.1' + buildToolsVersion = '29.0.3' + + ndkVersion '25.1.8937393' } dependencies { - implementation "com.android.support:support-compat:26.1.0" - implementation "com.android.support:support-core-utils:26.1.0" + implementation "com.android.support:support-compat:28.0.0" + implementation "com.android.support:support-core-utils:28.0.0" implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) } repositories { google() } + buildscript { repositories { google() } +} + +// Workaround to fix issue in Android Studio Chipmunk 2021.2.1 and later +// where opening a project would result in a 'prepareKotlinBuildScriptModel' +// not found error +if (!tasks.findByName("prepareKotlinBuildScriptModel")) { + tasks.register("prepareKotlinBuildScriptModel") {} } \ No newline at end of file diff --git a/Projects/Android/gradle/wrapper/gradle-wrapper.properties b/Projects/Android/gradle/wrapper/gradle-wrapper.properties index 7cb9b3b..352274c 100644 --- a/Projects/Android/gradle/wrapper/gradle-wrapper.properties +++ b/Projects/Android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip diff --git a/Projects/Android/jni/QuakeQuestSrc/QuakeQuest_OpenXR.c b/Projects/Android/jni/QuakeQuestSrc/QuakeQuest_OpenXR.c index f90564b..214da31 100644 --- a/Projects/Android/jni/QuakeQuestSrc/QuakeQuest_OpenXR.c +++ b/Projects/Android/jni/QuakeQuestSrc/QuakeQuest_OpenXR.c @@ -221,7 +221,7 @@ void VR_Init() //init randomiser srand(time(NULL)); - chdir("/sdcard/QuakeQuest"); + chdir((char*)getenv("QUAKEQUEST_DIR")); } extern int runStatus; diff --git a/Projects/Android/local.properties b/Projects/Android/local.properties index 4494cdd..14c1faf 100644 --- a/Projects/Android/local.properties +++ b/Projects/Android/local.properties @@ -5,5 +5,4 @@ # For customization when using a Version Control System, please read the # header note. #Thu Dec 12 20:21:11 GMT 2019 -ndk.dir=C\:\\Users\\Simon\\AppData\\Local\\Android\\Sdk\\ndk\\21.1.6352462 sdk.dir=C\:\\Users\\Simon\\AppData\\Local\\Android\\Sdk diff --git a/Projects/Android/settings.gradle b/Projects/Android/settings.gradle index a868f2f..71aad3f 100644 --- a/Projects/Android/settings.gradle +++ b/Projects/Android/settings.gradle @@ -1,4 +1 @@ -rootProject.projectDir = new File(settingsDir, '../..') rootProject.name = "QuakeQuest" - -include ':', 'Projects:Android' diff --git a/XrApp.gradle b/XrApp.gradle deleted file mode 100644 index d349e51..0000000 --- a/XrApp.gradle +++ /dev/null @@ -1,238 +0,0 @@ -import org.gradle.internal.os.OperatingSystem; -import com.android.ddmlib.AndroidDebugBridge -import com.android.ddmlib.IDevice -import com.android.ddmlib.CollectingOutputReceiver -import org.apache.tools.ant.taskdefs.condition.Os - -buildscript { - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:4.0.0' - } - - tasks.register("wrapper") -} - -class XrAppPlugin implements Plugin { - Project project = null - - void installApk( IDevice device, File apkFile, String applicationId ) { - project.logger.quiet "Installing ${applicationId} on device ${device.serialNumber}" - - String toinstall = "/data/local/tmp/toinstall.apk" - - try { - device.pushFile( apkFile.path, toinstall ) - } catch ( Exception e ) { - throw new RuntimeException( "Failed to push ${apkFile.path} to ${toinstall}. ${e}", e ) - } - - while ( true ) { - try { - device.installRemotePackage( toinstall, true ) - break - } catch ( Exception e ) { - project.logger.quiet "Failed to install ${applicationId} on device ${device.serialNumber} (${e}). Trying to uninstall first." - } - try { - device.uninstallPackage( applicationId ) - } catch ( Exception e ) { - throw new RuntimeException( "Failed to uninstall ${applicationId}. ${e}", e ) - } - } - } - - void stopApk( IDevice device, String packageName ) { - CollectingOutputReceiver receiver = new CollectingOutputReceiver() - device.executeShellCommand( "am force-stop ${packageName}", receiver ) - } - - void runApk( IDevice device, manifestFile ) { - CollectingOutputReceiver receiver = new CollectingOutputReceiver() - def activityClass = new XmlSlurper().parse( manifestFile ).application.activity.find{ it.'intent-filter'.find{ filter -> - return filter.action .find{it.'@android:name'.text() == 'android.intent.action.MAIN' } \ - && ( filter.category.find{it.'@android:name'.text() == 'android.intent.category.LAUNCHER'} \ - || filter.category.find{it.'@android:name'.text() == 'android.intent.category.INFO'} ) - }}.'@android:name' - def startActivity = "${project.android.defaultConfig.applicationId}/${activityClass}" - project.logger.quiet "Starting \'$startActivity\' on ${project.deviceMap.size()} devices:" - project.logger.quiet "- ${device.serialNumber}" - device.executeShellCommand( "am start $startActivity", receiver ) - } - - void apply( Project project ) { - this.project = project - - // FIXME: The Task.leftShift(Closure) method has been deprecated and is scheduled to be removed in Gradle 5.0. Please use Task.doLast(Action) instead. - project.task( "cleanWorkAround" ) { - description "Workaround for .externalNativeBuild not being deleted on clean" - }.doLast { - project.delete project.file( ".externalNativeBuild" ) - } - - project.android { - compileSdkVersion 26 - - defaultConfig { - minSdkVersion 24 - targetSdkVersion 25 - - externalNativeBuild { - ndk { - } - ndkBuild { - def numProcs = Runtime.runtime.availableProcessors() - arguments "V=0", "-j$numProcs", "-C$project.buildDir.parent", "APP_PLATFORM=android-24", "NDK_TOOLCHAIN_VERSION=clang", "APP_STL=c++_static" - } - } - } - - externalNativeBuild { - ndkBuild { - path 'jni/Android.mk' - } - } - - signingConfigs { - def keystorePath = (project.hasProperty('key.store')) ? - new File(project.getProperty('key.store')) : - project.file('android.debug.keystore') - - def keystorePassword = (project.hasProperty('key.store.password')) ? - project.getProperty('key.store.password') : 'android' - - def keystoreKeyAlias = (project.hasProperty('key.alias')) ? - project.getProperty('key.alias') : 'androiddebugkey' - - def keystoreKeyPassword = (project.hasProperty('key.alias.password')) ? - project.getProperty('key.alias.password') : 'android' - - debug { - storeFile keystorePath - storePassword keystorePassword - keyAlias keystoreKeyAlias - keyPassword keystoreKeyPassword - v2SigningEnabled true - } - - release { - storeFile keystorePath - storePassword keystorePassword - keyAlias keystoreKeyAlias - keyPassword keystoreKeyPassword - v2SigningEnabled true - } - } - - buildTypes { - debug { - signingConfig signingConfigs.debug - debuggable true - jniDebuggable true - - externalNativeBuild { - ndkBuild { - arguments "NDK_DEBUG=1","USE_ASAN=1" - } - } - } - - release { - signingConfig signingConfigs.release - debuggable false - jniDebuggable false - - externalNativeBuild { - ndkBuild { - arguments "NDK_DEBUG=0","USE_ASAN=0" - } - } - } - } - } - - // WORKAROUND: On Mac OS X, running ndk-build clean with a high num of parallel executions - // set may result in the following build error: rm: fts_read: No such file or directory. - // Currently, there isn't a good way to specify numProcs=1 only on clean. So, in order - // to work around the issue, delete the auto-generated .externalNativeBuild artifacts - // (where $numProcs specified) before executing the clean task. - project.clean.dependsOn project.cleanWorkAround - - project.clean { - // remove the auto-generated debug keystore (currently generated by python build script) - // delete "android.debug.keystore" - } - - project.afterEvaluate { - Task initDeviceList = project.task( "initDeviceList()" ).doLast { - project.ext.deviceMap = [ : ] - if (project.hasProperty( "should_install" ) == true) { - AndroidDebugBridge.initIfNeeded( false ) - AndroidDebugBridge bridge = AndroidDebugBridge.createBridge( project.android.getAdbExe().absolutePath, false ) - - long timeOut = 30000 // 30 sec - int sleepTime = 1000 - while ( !bridge.hasInitialDeviceList() && timeOut > 0 ) { - sleep( sleepTime ) - timeOut -= sleepTime - } - if ( timeOut <= 0 && !bridge.hasInitialDeviceList() ) { - throw new RuntimeException( "Timeout getting device list.", null ) - } - - // if a device is connected both physically and over the network, only include the physical ID - if ( project.hasProperty( "should_install" ) == true ) { - bridge.devices.split { it.getProperty( "ro.serialno" ) != it.serialNumber }.each { - it.collectEntries( project.deviceMap, { [ ( it.getProperty( "ro.serialno" )) : it ] } ) - } - } - } - } - - project.task( "stopApk", dependsOn: initDeviceList ) { - description "Stops app if currently running on device" - }.doLast { - project.deviceMap.each { deviceSerial, device -> - stopApk( device, android.defaultConfig.applicationId ) - } - } - - project.android.applicationVariants.all { variant -> - Task installAndRun = project.task( "installAndRun${variant.name.capitalize()}" ) { - dependsOn variant.assembleProvider.get() - dependsOn initDeviceList - onlyIf { project.hasProperty( "should_install" ) } - description "Installs and runs the APK file" - }.doLast { variant.outputs.each { output -> - if ( output.outputFile.exists() ) { - if ( project.deviceMap.size() == 0 ) { - project.logger.quiet "Install requested, but no devices found." - } else { - project.deviceMap.each { deviceSerial, device -> - installApk( device, output.outputFile, project.android.defaultConfig.applicationId ) - runApk( device, new File(output.processManifest.manifestOutputDirectory.get().asFile, "AndroidManifest.xml")) - } - } - } - } - } - variant.assembleProvider.get().finalizedBy installAndRun - } - } - } -} - -// Workaround to fix issue in Android Studio Chipmunk 2021.2.1 and later -// where opening a project would result in a 'prepareKotlinBuildScriptModel' -// not found error -if (!tasks.findByName("prepareKotlinBuildScriptModel")) { - tasks.register("prepareKotlinBuildScriptModel") {} -} - - - -apply plugin: XrAppPlugin diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 05092ac..0000000 --- a/build.gradle +++ /dev/null @@ -1,22 +0,0 @@ -buildscript { - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:4.0.0' - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} - diff --git a/gradle.properties b/gradle.properties index b38e197..a8083b7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,8 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx1536M \ +--add-exports=java.base/sun.nio.ch=ALL-UNNAMED \ +--add-opens=java.base/java.lang=ALL-UNNAMED \ +--add-opens=java.base/java.lang.reflect=ALL-UNNAMED \ +--add-opens=java.base/java.io=ALL-UNNAMED \ +--add-exports=jdk.unsupported/sun.misc=ALL-UNNAMED org.gradle.caching=true org.gradle.configureondemand=true diff --git a/java/com/drbeef/quakequest/GLES3JNIActivity.java b/java/com/drbeef/quakequest/GLES3JNIActivity.java index 0202b56..cf98383 100644 --- a/java/com/drbeef/quakequest/GLES3JNIActivity.java +++ b/java/com/drbeef/quakequest/GLES3JNIActivity.java @@ -21,6 +21,7 @@ import android.content.res.AssetManager; import android.os.Build; import android.os.Bundle; +import android.system.ErrnoException; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; @@ -66,6 +67,8 @@ import android.support.v4.content.ContextCompat; private SurfaceHolder mSurfaceHolder; private long mNativeHandle; + String dir; + private final boolean m_asynchronousTracking = false; @Override protected void onCreate( Bundle icicle ) @@ -78,6 +81,8 @@ import android.support.v4.content.ContextCompat; setContentView( mView ); mView.getHolder().addCallback( this ); + dir = getBaseContext().getExternalFilesDir(null).getAbsolutePath(); + // Force the screen to stay on, rather than letting it dim and shut off // while the user is watching a movie. getWindow().addFlags( WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON ); @@ -120,7 +125,12 @@ import android.support.v4.content.ContextCompat; if (permissionCount == 2) { // Permissions have already been granted. - create(); + try { + create(); + } catch (Exception ignored) + { + + } } } @@ -150,22 +160,23 @@ import android.support.v4.content.ContextCompat; checkPermissionsAndInitialize(); } - public void create() - { + public void create() throws ErrnoException { //This will copy the shareware version of quake if user doesn't have anything installed - copy_asset("/sdcard/QuakeQuest/id1", "pak0.pak"); - copy_asset("/sdcard/QuakeQuest/id1", "config.cfg"); - copy_asset("/sdcard/QuakeQuest", "commandline.txt"); + copy_asset(dir + "/id1", "pak0.pak"); + copy_asset(dir + "/id1", "config.cfg"); + copy_asset(dir, "commandline.txt"); + + setenv("QUAKEQUEST_DIR", dir, true); //Read these from a file and pass through commandLineParams = new String("quake"); //See if user is trying to use command line params - if(new File("/sdcard/QuakeQuest/commandline.txt").exists()) // should exist! + if(new File(dir + "/commandline.txt").exists()) // should exist! { BufferedReader br; try { - br = new BufferedReader(new FileReader("/sdcard/QuakeQuest/commandline.txt")); + br = new BufferedReader(new FileReader(dir + "/commandline.txt")); String s; StringBuilder sb=new StringBuilder(0); while ((s=br.readLine())!=null) diff --git a/local.properties b/local.properties index 4494cdd..14c1faf 100644 --- a/local.properties +++ b/local.properties @@ -5,5 +5,4 @@ # For customization when using a Version Control System, please read the # header note. #Thu Dec 12 20:21:11 GMT 2019 -ndk.dir=C\:\\Users\\Simon\\AppData\\Local\\Android\\Sdk\\ndk\\21.1.6352462 sdk.dir=C\:\\Users\\Simon\\AppData\\Local\\Android\\Sdk