Browse Source

Update Android java code (#7820)

Targets SDK 26 as required by the playstore.
Fixes screen auto-rotation closing game.
Hides on-screen navigation bar if present.

Update gradlew.
Fix display aspect on 18+/:9 displays (like a Samsung Galaxy S9).
Remove small app icons, not required.
Fix xml in unpacking activity.
Support Android permission: On Android 6.0+ you need to manually give write
permission (as required by google).
Background during unpacking (just a demo for now).
Material Design: no more Android 2 interface.
Immersive mode (Android 4.4+ - hide NavBar for fullscreen mode).
Maksim 5 years ago
parent
commit
f70f7875e2

+ 1 - 0
.gitignore

@@ -90,6 +90,7 @@ locale/
 *.ninja
 .ninja*
 *.gch
+*.iml
 test_config.h
 cmake-build-debug/
 cmake-build-release/

+ 33 - 24
build/android/build.gradle

@@ -1,12 +1,17 @@
 buildscript {
 	repositories {
-		mavenCentral()
-		jcenter()
-		google()
 		maven { url 'https://maven.google.com' }
+		jcenter()
 	}
 	dependencies {
-		classpath "com.android.tools.build:gradle:3.1.3"
+		classpath 'com.android.tools.build:gradle:3.1.3'
+	}
+}
+
+allprojects {
+	repositories {
+		maven { url 'https://maven.google.com' }
+		jcenter()
 	}
 }
 
@@ -20,21 +25,21 @@ def sqlite3_version = "3240000"
 apply plugin: "com.android.application"
 
 android {
-	compileSdkVersion 26
-	buildToolsVersion "26.0.3"
+	compileSdkVersion 28
+	buildToolsVersion "28.0.3"
 
 	defaultConfig {
 		versionCode 20
 		versionName "${System.env.VERSION_STR}.${versionCode}"
 		minSdkVersion 14
-		targetSdkVersion 14
+		targetSdkVersion 28
 		applicationId "net.minetest.minetest"
-		manifestPlaceholders = [ package: "net.minetest.minetest", project: project.name ]
+		manifestPlaceholders = [package: "net.minetest.minetest", project: project.name]
 		ndk {
 			// Specifies the ABI configurations of your native
 			// libraries Gradle should build and package with your APK.
-			abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a',
-			'arm64-v8a'
+			// abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
+			abiFilters 'armeabi-v7a', 'x86'
 		}
 	}
 
@@ -63,58 +68,58 @@ android {
 	}
 }
 
-task cleanAssets(type:Delete) {
+task cleanAssets(type: Delete) {
 	delete 'src/main/assets'
 }
 
-task cleanIconv(type:Delete) {
+task cleanIconv(type: Delete) {
 	delete 'deps/libiconv'
 }
 
-task cleanIrrlicht(type:Delete) {
+task cleanIrrlicht(type: Delete) {
 	delete 'deps/irrlicht'
 }
 
-task cleanLevelDB(type:Delete) {
+task cleanLevelDB(type: Delete) {
 	delete 'deps/leveldb'
 }
 
-task cleanCURL(type:Delete) {
+task cleanCURL(type: Delete) {
 	delete 'deps/curl'
 	delete 'deps/curl-' + curl_version
 }
 
-task cleanOpenSSL(type:Delete) {
+task cleanOpenSSL(type: Delete) {
 	delete 'deps/openssl'
 	delete 'deps/openssl-' + openssl_version
 	delete 'deps/openssl-' + openssl_version + '.tar.gz'
 }
 
-task cleanOpenAL(type:Delete) {
+task cleanOpenAL(type: Delete) {
 	delete 'deps/openal-soft'
 }
 
-task cleanFreetype(type:Delete) {
+task cleanFreetype(type: Delete) {
 	delete 'deps/freetype2-android'
 }
 
-task cleanOgg(type:Delete) {
+task cleanOgg(type: Delete) {
 	delete 'deps/libvorbis-libogg-android'
 }
 
-task cleanSQLite3(type:Delete) {
+task cleanSQLite3(type: Delete) {
 	delete 'deps/sqlite-amalgamation-' + sqlite3_version
 	delete 'deps/sqlite-amalgamation-' + sqlite3_version + '.zip'
 }
 
-task cleanGMP(type:Delete) {
+task cleanGMP(type: Delete) {
 	delete 'deps/gmp'
 	delete 'deps/gmp-' + gmp_version
 }
 
-task cleanAll(type:Delete, dependsOn:[clean,cleanAssets,cleanIconv,
-	cleanFreetype,cleanIrrlicht,cleanLevelDB,cleanSQLite3,cleanCURL,
-	cleanOpenSSL,cleanOpenAL,cleanOgg,cleanGMP]) {
+task cleanAll(type: Delete, dependsOn: [clean, cleanAssets, cleanIconv,
+										cleanFreetype, cleanIrrlicht, cleanLevelDB, cleanSQLite3, cleanCURL,
+										cleanOpenSSL, cleanOpenAL, cleanOgg, cleanGMP]) {
 	delete 'deps'
 	delete 'gen'
 	delete 'libs'
@@ -123,3 +128,7 @@ task cleanAll(type:Delete, dependsOn:[clean,cleanAssets,cleanIconv,
 	delete 'Debug'
 	delete 'and_env'
 }
+
+dependencies {
+	implementation 'com.android.support:support-v4:28.0.0'
+}

BIN
build/android/gradle/wrapper/gradle-wrapper.jar


+ 2 - 2
build/android/gradle/wrapper/gradle-wrapper.properties

@@ -1,6 +1,6 @@
-#Sat Aug 27 20:10:09 CEST 2016
+#Mon Oct 15 00:47:03 CEST 2018
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip

+ 43 - 35
build/android/gradlew

@@ -1,4 +1,4 @@
-#!/usr/bin/env bash
+#!/usr/bin/env sh
 
 ##############################################################################
 ##
@@ -6,20 +6,38 @@
 ##
 ##############################################################################
 
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
 
 APP_NAME="Gradle"
 APP_BASE_NAME=`basename "$0"`
 
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
 # Use the maximum available, or set MAX_FD != -1 to use that value.
 MAX_FD="maximum"
 
-warn ( ) {
+warn () {
     echo "$*"
 }
 
-die ( ) {
+die () {
     echo
     echo "$*"
     echo
@@ -30,6 +48,7 @@ die ( ) {
 cygwin=false
 msys=false
 darwin=false
+nonstop=false
 case "`uname`" in
   CYGWIN* )
     cygwin=true
@@ -40,31 +59,11 @@ case "`uname`" in
   MINGW* )
     msys=true
     ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
 esac
 
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
-    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
-APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
-
 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 
 # Determine the Java command to use to start the JVM.
@@ -90,7 +89,7 @@ location of your Java installation."
 fi
 
 # Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
     MAX_FD_LIMIT=`ulimit -H -n`
     if [ $? -eq 0 ] ; then
         if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -114,6 +113,7 @@ fi
 if $cygwin ; then
     APP_HOME=`cygpath --path --mixed "$APP_HOME"`
     CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
 
     # We build the pattern for arguments to be converted via cygpath
     ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
@@ -154,11 +154,19 @@ if $cygwin ; then
     esac
 fi
 
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
-    JVM_OPTS=("$@")
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
 }
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
 
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
+exec "$JAVACMD" "$@"

+ 4 - 10
build/android/gradlew.bat

@@ -8,14 +8,14 @@
 @rem Set local scope for the variables with windows NT shell
 if "%OS%"=="Windows_NT" setlocal
 
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
 set DIRNAME=%~dp0
 if "%DIRNAME%" == "" set DIRNAME=.
 set APP_BASE_NAME=%~n0
 set APP_HOME=%DIRNAME%
 
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
 @rem Find java.exe
 if defined JAVA_HOME goto findJavaFromJavaHome
 
@@ -46,10 +46,9 @@ echo location of your Java installation.
 goto fail
 
 :init
-@rem Get command-line arguments, handling Windowz variants
+@rem Get command-line arguments, handling Windows variants
 
 if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
 
 :win9xME_args
 @rem Slurp the command line arguments.
@@ -60,11 +59,6 @@ set _SKIP=2
 if "x%~1" == "x" goto execute
 
 set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
 
 :execute
 @rem Setup the command line

+ 2 - 1
build/android/src/debug/AndroidManifest.xml

@@ -1,4 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android">
-	<uses-permission android:name="android.permission.SET_DEBUG_APP" />
+
+    <uses-permission android:name="android.permission.SET_DEBUG_APP" />
 </manifest>

+ 46 - 21
build/android/src/main/AndroidManifest.xml

@@ -1,34 +1,59 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-		package="net.minetest.minetest"
-		android:installLocation="auto">
-	<uses-feature android:glEsVersion="0x00010000" android:required="true"/>
+	package="net.minetest.minetest"
+	android:installLocation="auto">
+
+	<uses-feature
+		android:glEsVersion="0x00010000"
+		android:required="true" />
+
 	<uses-permission android:name="android.permission.INTERNET" />
-	<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
 	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-	<application android:icon="@drawable/irr_icon"
+
+	<application
+		android:allowBackup="true"
+		android:icon="@mipmap/ic_launcher"
+		android:label="${project}"
+		android:resizeableActivity="false">
+
+		<meta-data
+			android:name="android.max_aspect"
+			android:value="2.1" />
+
+		<activity
+			android:name=".MainActivity"
+			android:configChanges="orientation|keyboardHidden|navigation|screenSize"
 			android:label="${project}"
-			android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
-			android:allowBackup="true">
-		<activity android:name=".MtNativeActivity"
-				android:label="${project}"
-				android:launchMode="singleTask"
-				android:configChanges="orientation|keyboard|keyboardHidden|navigation"
-				android:screenOrientation="sensorLandscape"
-				android:clearTaskOnLaunch="true">
+			android:launchMode="singleTask"
+			android:screenOrientation="sensorLandscape"
+			android:theme="@style/AppTheme">
 			<intent-filter>
 				<action android:name="android.intent.action.MAIN" />
 				<category android:name="android.intent.category.LAUNCHER" />
 			</intent-filter>
-			<meta-data android:name="android.app.lib_name" android:value="minetest" />
 		</activity>
-		<activity android:name=".MinetestTextEntry"
-				android:theme="@style/Theme.Transparent"
-				android:excludeFromRecents="true">
-		</activity>
-		<activity android:name=".MinetestAssetCopy"
-				android:theme="@style/Theme.Transparent"
-				android:excludeFromRecents="true">
+		<activity
+			android:name=".MtNativeActivity"
+			android:configChanges="orientation|keyboard|keyboardHidden|navigation|screenSize|smallestScreenSize"
+			android:hardwareAccelerated="true"
+			android:launchMode="singleTask"
+			android:screenOrientation="sensorLandscape"
+			android:theme="@style/AppTheme">
+			<intent-filter>
+				<action android:name="android.intent.action.MAIN" />
+			</intent-filter>
+			<meta-data
+				android:name="android.app.lib_name"
+				android:value="minetest" />
 		</activity>
+		<activity
+			android:name=".MinetestTextEntry"
+			android:configChanges="keyboardHidden|orientation|screenSize"
+			android:theme="@style/Theme.Dialog"
+			android:windowSoftInputMode="stateAlwaysHidden"/>
+		<activity
+			android:name=".MinetestAssetCopy"
+			android:screenOrientation="sensorLandscape"
+			android:theme="@style/AppTheme"/>
 	</application>
 </manifest>

+ 79 - 0
build/android/src/main/java/net.minetest.minetest/MainActivity.java

@@ -0,0 +1,79 @@
+package net.minetest.minetest;
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class MainActivity extends Activity {
+
+	private final static int PERMISSIONS = 1;
+	private static final String[] REQUIRED_SDK_PERMISSIONS = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE};
+
+	@Override
+	public void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+			checkPermission();
+		} else {
+			next();
+		}
+	}
+
+	protected void checkPermission() {
+		final List<String> missingPermissions = new ArrayList<String>();
+		// check required permission
+		for (final String permission : REQUIRED_SDK_PERMISSIONS) {
+			final int result = ContextCompat.checkSelfPermission(this, permission);
+			if (result != PackageManager.PERMISSION_GRANTED) {
+				missingPermissions.add(permission);
+			}
+		}
+		if (!missingPermissions.isEmpty()) {
+			// request permission
+			final String[] permissions = missingPermissions
+					.toArray(new String[missingPermissions.size()]);
+			ActivityCompat.requestPermissions(this, permissions, PERMISSIONS);
+		} else {
+			final int[] grantResults = new int[REQUIRED_SDK_PERMISSIONS.length];
+			Arrays.fill(grantResults, PackageManager.PERMISSION_GRANTED);
+			onRequestPermissionsResult(PERMISSIONS, REQUIRED_SDK_PERMISSIONS,
+					grantResults);
+		}
+	}
+
+	@Override
+	public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
+										   @NonNull int[] grantResults) {
+		switch (requestCode) {
+			case PERMISSIONS:
+				for (int index = 0; index < permissions.length; index++) {
+					if (grantResults[index] != PackageManager.PERMISSION_GRANTED) {
+						// permission not granted - toast and exit
+						Toast.makeText(this, R.string.not_granted, Toast.LENGTH_LONG).show();
+						finish();
+						return;
+					}
+				}
+				// permission were granted - run
+				next();
+				break;
+		}
+	}
+
+	public void next() {
+		Intent intent = new Intent(this, MtNativeActivity.class);
+		intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+		startActivity(intent);
+	}
+}

+ 169 - 212
build/android/src/main/java/net.minetest.minetest/MinetestAssetCopy.java

@@ -1,416 +1,373 @@
 package net.minetest.minetest;
 
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.util.Vector;
-import java.util.Iterator;
-import java.lang.Object;
-
 import android.app.Activity;
 import android.content.res.AssetFileDescriptor;
-
 import android.os.AsyncTask;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
 import android.util.Log;
 import android.view.Display;
+import android.view.View;
 import android.widget.ProgressBar;
 import android.widget.TextView;
-import android.graphics.Rect;
-import android.graphics.Paint;
-import android.text.TextPaint;
 
-public class MinetestAssetCopy extends Activity
-{
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.Vector;
+
+public class MinetestAssetCopy extends Activity {
+	ProgressBar m_ProgressBar;
+	TextView m_Filename;
+	copyAssetTask m_AssetCopy;
+
 	@Override
-	public void onCreate(Bundle savedInstanceState)
-	{
+	public void onCreate(Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
-		
 		setContentView(R.layout.assetcopy);
-		
-		m_ProgressBar = (ProgressBar) findViewById(R.id.progressBar1);
-		m_Filename = (TextView) findViewById(R.id.textView1);
-		
+		m_ProgressBar = findViewById(R.id.progressBar1);
+		m_Filename = findViewById(R.id.textView1);
 		Display display = getWindowManager().getDefaultDisplay();
 		m_ProgressBar.getLayoutParams().width = (int) (display.getWidth() * 0.8);
 		m_ProgressBar.invalidate();
-		
+
 		/* check if there's already a copy in progress and reuse in case it is*/
-		MinetestAssetCopy prevActivity = 
+		MinetestAssetCopy prevActivity =
 				(MinetestAssetCopy) getLastNonConfigurationInstance();
-		if(prevActivity!= null) {
+		if (prevActivity != null) {
 			m_AssetCopy = prevActivity.m_AssetCopy;
-		}
-		else {
+		} else {
 			m_AssetCopy = new copyAssetTask();
 			m_AssetCopy.execute();
 		}
 	}
-	
+
+	@Override
+	protected void onResume() {
+		super.onResume();
+		makeFullScreen();
+	}
+
+	public void makeFullScreen() {
+		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+			this.getWindow().getDecorView().setSystemUiVisibility(
+					View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+			);
+		}
+	}
+
+	@Override
+	public void onWindowFocusChanged(boolean hasFocus) {
+		super.onWindowFocusChanged(hasFocus);
+		if (hasFocus) {
+			makeFullScreen();
+		}
+	}
+
 	/* preserve asset copy background task to prevent restart of copying */
 	/* this way of doing it is not recommended for latest android version */
 	/* but the recommended way isn't available on android 2.x */
-	public Object onRetainNonConfigurationInstance()
-	{
+	public Object onRetainNonConfigurationInstance() {
 		return this;
 	}
-	
-	ProgressBar m_ProgressBar;
-	TextView m_Filename;
-	
-	copyAssetTask m_AssetCopy;
-	
-	private class copyAssetTask extends AsyncTask<String, Integer, String>
-	{
-		private long getFullSize(String filename)
-		{
+
+	private class copyAssetTask extends AsyncTask<String, Integer, String> {
+		boolean m_copy_started = false;
+		String m_Foldername = "media";
+		Vector<String> m_foldernames;
+		Vector<String> m_filenames;
+		Vector<String> m_tocopy;
+		Vector<String> m_asset_size_unknown;
+
+		private long getFullSize(String filename) {
 			long size = 0;
 			try {
 				InputStream src = getAssets().open(filename);
 				byte[] buf = new byte[4096];
-				
+
 				int len = 0;
-				while ((len = src.read(buf)) > 0)
-				{
+				while ((len = src.read(buf)) > 0) {
 					size += len;
 				}
-			}
-			catch (IOException e)
-			{
+			} catch (IOException e) {
 				e.printStackTrace();
 			}
 			return size;
 		}
 
 		@Override
-		protected String doInBackground(String... files)
-		{
-			m_foldernames  = new Vector<String>();
-			m_filenames    = new Vector<String>();
-			m_tocopy       = new Vector<String>();
+		protected String doInBackground(String... files) {
+			m_foldernames = new Vector<String>();
+			m_filenames = new Vector<String>();
+			m_tocopy = new Vector<String>();
 			m_asset_size_unknown = new Vector<String>();
-			String baseDir = 
+			String baseDir =
 					Environment.getExternalStorageDirectory().getAbsolutePath()
-					+ "/";
-			
-			
+							+ "/";
+
+
 			// prepare temp folder
 			File TempFolder = new File(baseDir + "Minetest/tmp/");
-			
-			if (!TempFolder.exists())
-			{
+
+			if (!TempFolder.exists()) {
 				TempFolder.mkdir();
-			}
-			else {
+			} else {
 				File[] todel = TempFolder.listFiles();
-				
-				for(int i=0; i < todel.length; i++)
-				{
-					Log.v("MinetestAssetCopy","deleting: " + todel[i].getAbsolutePath());
+
+				for (int i = 0; i < todel.length; i++) {
+					Log.v("MinetestAssetCopy", "deleting: " + todel[i].getAbsolutePath());
 					todel[i].delete();
 				}
 			}
-			
+
 			// add a .nomedia file
 			try {
 				OutputStream dst = new FileOutputStream(baseDir + "Minetest/.nomedia");
 				dst.close();
 			} catch (IOException e) {
-				Log.e("MinetestAssetCopy","Failed to create .nomedia file");
+				Log.e("MinetestAssetCopy", "Failed to create .nomedia file");
 				e.printStackTrace();
 			}
-			
-			
+
+
 			// build lists from prepared data
 			BuildFolderList();
 			BuildFileList();
-			
+
 			// scan filelist
 			ProcessFileList();
-			
+
 			// doing work
 			m_copy_started = true;
 			m_ProgressBar.setMax(m_tocopy.size());
-			
-			for (int i = 0; i < m_tocopy.size(); i++)
-			{
-				try
-				{
+
+			for (int i = 0; i < m_tocopy.size(); i++) {
+				try {
 					String filename = m_tocopy.get(i);
 					publishProgress(i);
-					
+
 					boolean asset_size_unknown = false;
 					long filesize = -1;
-					
-					if (m_asset_size_unknown.contains(filename))
-					{
+
+					if (m_asset_size_unknown.contains(filename)) {
 						File testme = new File(baseDir + "/" + filename);
-						
-						if(testme.exists())
-						{
+
+						if (testme.exists()) {
 							filesize = testme.length();
 						}
 						asset_size_unknown = true;
 					}
-					
+
 					InputStream src;
-					try
-					{
+					try {
 						src = getAssets().open(filename);
 					} catch (IOException e) {
-						Log.e("MinetestAssetCopy","Copying file: " + filename + " FAILED (not in assets)");
+						Log.e("MinetestAssetCopy", "Copying file: " + filename + " FAILED (not in assets)");
 						e.printStackTrace();
 						continue;
 					}
-					
+
 					// Transfer bytes from in to out
-					byte[] buf = new byte[1*1024];
+					byte[] buf = new byte[1024];
 					int len = src.read(buf, 0, 1024);
-					
+
 					/* following handling is crazy but we need to deal with    */
 					/* compressed assets.Flash chips limited livetime due to   */
 					/* write operations, we can't allow large files to destroy */
 					/* users flash.                                            */
-					if (asset_size_unknown)
-					{
-						if ( (len > 0) && (len < buf.length) && (len == filesize))
-						{
+					if (asset_size_unknown) {
+						if ((len > 0) && (len < buf.length) && (len == filesize)) {
 							src.close();
 							continue;
 						}
-						
-						if (len == buf.length)
-						{
+
+						if (len == buf.length) {
 							src.close();
 							long size = getFullSize(filename);
-							if ( size == filesize)
-							{
+							if (size == filesize) {
 								continue;
 							}
 							src = getAssets().open(filename);
 							len = src.read(buf, 0, 1024);
 						}
 					}
-					if (len > 0)
-					{
+					if (len > 0) {
 						int total_filesize = 0;
 						OutputStream dst;
-						try
-						{
+						try {
 							dst = new FileOutputStream(baseDir + "/" + filename);
 						} catch (IOException e) {
-							Log.e("MinetestAssetCopy","Copying file: " + baseDir +
-							"/" + filename + " FAILED (couldn't open output file)");
+							Log.e("MinetestAssetCopy", "Copying file: " + baseDir +
+									"/" + filename + " FAILED (couldn't open output file)");
 							e.printStackTrace();
 							src.close();
 							continue;
 						}
 						dst.write(buf, 0, len);
 						total_filesize += len;
-						
-						while ((len = src.read(buf)) > 0)
-						{
+
+						while ((len = src.read(buf)) > 0) {
 							dst.write(buf, 0, len);
 							total_filesize += len;
 						}
-						
+
 						dst.close();
-						Log.v("MinetestAssetCopy","Copied file: " +
-									m_tocopy.get(i) + " (" + total_filesize +
-									" bytes)");
-					}
-					else if (len < 0)
-					{
-						Log.e("MinetestAssetCopy","Copying file: " +
+						Log.v("MinetestAssetCopy", "Copied file: " +
+								m_tocopy.get(i) + " (" + total_filesize +
+								" bytes)");
+					} else if (len < 0) {
+						Log.e("MinetestAssetCopy", "Copying file: " +
 								m_tocopy.get(i) + " failed, size < 0");
 					}
 					src.close();
-				} 
-				catch (IOException e)
-				{
-					Log.e("MinetestAssetCopy","Copying file: " +
+				} catch (IOException e) {
+					Log.e("MinetestAssetCopy", "Copying file: " +
 							m_tocopy.get(i) + " failed");
 					e.printStackTrace();
 				}
 			}
 			return "";
 		}
-		
-		
+
 		/**
 		 * update progress bar
 		 */
-		protected void onProgressUpdate(Integer... progress)
-		{
-			
-			if (m_copy_started)
-			{
+		protected void onProgressUpdate(Integer... progress) {
+
+			if (m_copy_started) {
 				boolean shortened = false;
 				String todisplay = m_tocopy.get(progress[0]);
 				m_ProgressBar.setProgress(progress[0]);
 				m_Filename.setText(todisplay);
-			}
-			else
-			{
+			} else {
 				boolean shortened = false;
 				String todisplay = m_Foldername;
 				String full_text = "scanning " + todisplay + " ...";
 				m_Filename.setText(full_text);
 			}
 		}
-		
+
 		/**
-		 * check al files and folders in filelist
+		 * check all files and folders in filelist
 		 */
-		protected void ProcessFileList()
-		{
-			String FlashBaseDir = 
+		protected void ProcessFileList() {
+			String FlashBaseDir =
 					Environment.getExternalStorageDirectory().getAbsolutePath();
-			
+
 			Iterator itr = m_filenames.iterator();
-			
-			while (itr.hasNext())
-			{
+
+			while (itr.hasNext()) {
 				String current_path = (String) itr.next();
 				String FlashPath = FlashBaseDir + "/" + current_path;
-				
-				if (isAssetFolder(current_path))
-				{
+
+				if (isAssetFolder(current_path)) {
 					/* store information and update gui */
 					m_Foldername = current_path;
 					publishProgress(0);
-					
+
 					/* open file in order to check if it's a folder */
 					File current_folder = new File(FlashPath);
-					if (!current_folder.exists())
-					 {
-						if (!current_folder.mkdirs())
-						{
-							Log.e("MinetestAssetCopy","\t failed create folder: " +
+					if (!current_folder.exists()) {
+						if (!current_folder.mkdirs()) {
+							Log.e("MinetestAssetCopy", "\t failed create folder: " +
 									FlashPath);
-						}
-						else
-						{
-							Log.v("MinetestAssetCopy","\t created folder: " +
+						} else {
+							Log.v("MinetestAssetCopy", "\t created folder: " +
 									FlashPath);
 						}
 					}
-					
+
 					continue;
 				}
-				
+
 				/* if it's not a folder it's most likely a file */
 				boolean refresh = true;
-				
+
 				File testme = new File(FlashPath);
-				
+
 				long asset_filesize = -1;
 				long stored_filesize = -1;
-				
-				if (testme.exists())
-				{
-					try
-					{
+
+				if (testme.exists()) {
+					try {
 						AssetFileDescriptor fd = getAssets().openFd(current_path);
-						asset_filesize         = fd.getLength();
+						asset_filesize = fd.getLength();
 						fd.close();
-					} 
-					catch (IOException e)
-					{
+					} catch (IOException e) {
 						refresh = true;
 						m_asset_size_unknown.add(current_path);
-						Log.e("MinetestAssetCopy","Failed to open asset file \"" +
+						Log.e("MinetestAssetCopy", "Failed to open asset file \"" +
 								FlashPath + "\" for size check");
 					}
-					
+
 					stored_filesize = testme.length();
-					
-					if (asset_filesize == stored_filesize)
-					{
+
+					if (asset_filesize == stored_filesize) {
 						refresh = false;
 					}
-					
+
 				}
-				
-				if (refresh)
-				{
+
+				if (refresh) {
 					m_tocopy.add(current_path);
 				}
 			}
 		}
-		
+
 		/**
 		 * read list of folders prepared on package build
 		 */
-		protected void BuildFolderList()
-		{
-			try
-			{
+		protected void BuildFolderList() {
+			try {
 				InputStream is = getAssets().open("index.txt");
 				BufferedReader reader = new BufferedReader(new InputStreamReader(is));
-		
+
 				String line = reader.readLine();
-				while (line != null)
-				{
+				while (line != null) {
 					m_foldernames.add(line);
 					line = reader.readLine();
 				}
 				is.close();
-			} catch (IOException e1)
-			{
-				Log.e("MinetestAssetCopy","Error on processing index.txt");
+			} catch (IOException e1) {
+				Log.e("MinetestAssetCopy", "Error on processing index.txt");
 				e1.printStackTrace();
 			}
 		}
-		
+
 		/**
 		 * read list of asset files prepared on package build
 		 */
-		protected void BuildFileList()
-		{
+		protected void BuildFileList() {
 			long entrycount = 0;
-			try
-			{
+			try {
 				InputStream is = getAssets().open("filelist.txt");
 				BufferedReader reader = new BufferedReader(new InputStreamReader(is));
-		
+
 				String line = reader.readLine();
-				while (line != null)
-				{
+				while (line != null) {
 					m_filenames.add(line);
 					line = reader.readLine();
-					entrycount ++;
+					entrycount++;
 				}
 				is.close();
-			}
-			catch (IOException e1)
-			{
-				Log.e("MinetestAssetCopy","Error on processing filelist.txt");
+			} catch (IOException e1) {
+				Log.e("MinetestAssetCopy", "Error on processing filelist.txt");
 				e1.printStackTrace();
 			}
 		}
-		
-		protected void onPostExecute (String result)
-		{
+
+		protected void onPostExecute(String result) {
 			finish();
 		}
-		
-		protected boolean isAssetFolder(String path)
-		{
+
+		protected boolean isAssetFolder(String path) {
 			return m_foldernames.contains(path);
 		}
-		
-		boolean m_copy_started = false;
-		String m_Foldername = "media";
-		Vector<String> m_foldernames;
-		Vector<String> m_filenames;
-		Vector<String> m_tocopy;
-		Vector<String> m_asset_size_unknown;
 	}
 }

+ 23 - 27
build/android/src/main/java/net.minetest.minetest/MinetestTextEntry.java

@@ -6,63 +6,59 @@ import android.content.DialogInterface;
 import android.content.Intent;
 import android.os.Bundle;
 import android.text.InputType;
-import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.View.OnKeyListener;
 import android.widget.EditText;
 
 public class MinetestTextEntry extends Activity {
+	private final int MultiLineTextInput = 1;
+	private final int SingleLineTextInput = 2;
+	private final int SingleLinePasswordInput = 3;
 	public AlertDialog mTextInputDialog;
 	public EditText mTextInputWidget;
-	
-	private final int MultiLineTextInput              = 1;
-	private final int SingleLineTextInput             = 2;
-	private final int SingleLinePasswordInput         = 3;
-	
+
 	@Override
 	public void onCreate(Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
-		
 		Bundle b = getIntent().getExtras();
 		String acceptButton = b.getString("EnterButton");
-		String hint         = b.getString("hint");
-		String current      = b.getString("current");
-		int    editType     = b.getInt("editType");
-		
+		String hint = b.getString("hint");
+		String current = b.getString("current");
+		int editType = b.getInt("editType");
+
 		AlertDialog.Builder builder = new AlertDialog.Builder(this);
 		mTextInputWidget = new EditText(this);
 		mTextInputWidget.setHint(hint);
 		mTextInputWidget.setText(current);
 		mTextInputWidget.setMinWidth(300);
 		if (editType == SingleLinePasswordInput) {
-			mTextInputWidget.setInputType(InputType.TYPE_CLASS_TEXT | 
+			mTextInputWidget.setInputType(InputType.TYPE_CLASS_TEXT |
 					InputType.TYPE_TEXT_VARIATION_PASSWORD);
-		}
-		else {
+		} else {
 			mTextInputWidget.setInputType(InputType.TYPE_CLASS_TEXT);
 		}
-		
-		
+
 		builder.setView(mTextInputWidget);
-		
+
 		if (editType == MultiLineTextInput) {
 			builder.setPositiveButton(acceptButton, new DialogInterface.OnClickListener() {
-				public void onClick(DialogInterface dialog, int whichButton) 
-				{ pushResult(mTextInputWidget.getText().toString()); }
-				});
+				public void onClick(DialogInterface dialog, int whichButton) {
+					pushResult(mTextInputWidget.getText().toString());
+				}
+			});
 		}
-		
+
 		builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
 			public void onCancel(DialogInterface dialog) {
 				cancelDialog();
 			}
 		});
-		
+
 		mTextInputWidget.setOnKeyListener(new OnKeyListener() {
 			@Override
 			public boolean onKey(View view, int KeyCode, KeyEvent event) {
-				if ( KeyCode == KeyEvent.KEYCODE_ENTER){
+				if (KeyCode == KeyEvent.KEYCODE_ENTER) {
 
 					pushResult(mTextInputWidget.getText().toString());
 					return true;
@@ -70,19 +66,19 @@ public class MinetestTextEntry extends Activity {
 				return false;
 			}
 		});
-		
+
 		mTextInputDialog = builder.create();
 		mTextInputDialog.show();
 	}
-	
+
 	public void pushResult(String text) {
 		Intent resultData = new Intent();
 		resultData.putExtra("text", text);
-		setResult(Activity.RESULT_OK,resultData);
+		setResult(Activity.RESULT_OK, resultData);
 		mTextInputDialog.dismiss();
 		finish();
 	}
-	
+
 	public void cancelDialog() {
 		setResult(Activity.RESULT_CANCELED);
 		mTextInputDialog.dismiss();

+ 39 - 26
build/android/src/main/java/net.minetest.minetest/MtNativeActivity.java

@@ -2,23 +2,55 @@ package net.minetest.minetest;
 
 import android.app.NativeActivity;
 import android.content.Intent;
+import android.os.Build;
 import android.os.Bundle;
-import android.util.Log;
+import android.view.View;
 import android.view.WindowManager;
 
 public class MtNativeActivity extends NativeActivity {
+
+	static {
+		System.loadLibrary("openal");
+		System.loadLibrary("ogg");
+		System.loadLibrary("vorbis");
+		System.loadLibrary("gmp");
+		System.loadLibrary("iconv");
+		System.loadLibrary("minetest");
+	}
+
+	private int m_MessagReturnCode;
+	private String m_MessageReturnValue;
+
+	public static native void putMessageBoxResult(String text);
+
 	@Override
 	public void onCreate(Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
 		getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
 		m_MessagReturnCode = -1;
 		m_MessageReturnValue = "";
+	}
+
+	@Override
+	protected void onResume() {
+		super.onResume();
+		makeFullScreen();
+	}
 
+	public void makeFullScreen() {
+		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+			this.getWindow().getDecorView().setSystemUiVisibility(
+					View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+			);
+		}
 	}
 
 	@Override
-	public void onDestroy() {
-		super.onDestroy();
+	public void onWindowFocusChanged(boolean hasFocus) {
+		super.onWindowFocusChanged(hasFocus);
+		if (hasFocus) {
+			makeFullScreen();
+		}
 	}
 
 	public void copyAssets() {
@@ -27,7 +59,7 @@ public class MtNativeActivity extends NativeActivity {
 	}
 
 	public void showDialog(String acceptButton, String hint, String current,
-			int editType) {
+						   int editType) {
 
 		Intent intent = new Intent(this, MinetestTextEntry.class);
 		Bundle params = new Bundle();
@@ -38,11 +70,9 @@ public class MtNativeActivity extends NativeActivity {
 		intent.putExtras(params);
 		startActivityForResult(intent, 101);
 		m_MessageReturnValue = "";
-		m_MessagReturnCode   = -1;
+		m_MessagReturnCode = -1;
 	}
 
-	public static native void putMessageBoxResult(String text);
-
 	/* ugly code to workaround putMessageBoxResult not beeing found */
 	public int getDialogState() {
 		return m_MessagReturnCode;
@@ -67,32 +97,15 @@ public class MtNativeActivity extends NativeActivity {
 
 	@Override
 	protected void onActivityResult(int requestCode, int resultCode,
-			Intent data) {
+									Intent data) {
 		if (requestCode == 101) {
 			if (resultCode == RESULT_OK) {
 				String text = data.getStringExtra("text");
 				m_MessagReturnCode = 0;
 				m_MessageReturnValue = text;
-			}
-			else {
+			} else {
 				m_MessagReturnCode = 1;
 			}
 		}
 	}
-
-	static {
-		System.loadLibrary("openal");
-		System.loadLibrary("ogg");
-		System.loadLibrary("vorbis");
-		System.loadLibrary("gmp");
-		System.loadLibrary("iconv");
-
-		// We don't have to load libminetest.so ourselves,
-		// but if we do, we get nicer logcat errors when
-		// loading fails.
-		System.loadLibrary("minetest");
-	}
-
-	private int m_MessagReturnCode;
-	private String m_MessageReturnValue;
 }

BIN
build/android/src/main/res/drawable-hdpi/irr_icon.png


BIN
build/android/src/main/res/drawable-ldpi/irr_icon.png


BIN
build/android/src/main/res/drawable-mdpi/irr_icon.png


BIN
build/android/src/main/res/drawable-xhdpi/irr_icon.png


BIN
build/android/src/main/res/drawable/background.png


+ 4 - 0
build/android/src/main/res/drawable/bg.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+	android:src="@drawable/background"
+	android:tileMode="repeat" />

+ 20 - 20
build/android/src/main/res/layout/assetcopy.xml

@@ -1,24 +1,24 @@
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    android:orientation="vertical" >
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+	android:id="@+id/activity_main"
+	android:layout_width="match_parent"
+	android:layout_height="match_parent">
 
-    <ProgressBar
-        android:id="@+id/progressBar1"
-        style="?android:attr/progressBarStyleHorizontal"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical" />
+	<ProgressBar
+		android:id="@+id/progressBar1"
+		style="?android:attr/progressBarStyleHorizontal"
+		android:layout_width="match_parent"
+		android:layout_height="30dp"
+		android:layout_centerInParent="true"
+		android:layout_marginLeft="90dp"
+		android:layout_marginRight="90dp" />
 
-    <TextView
-        android:id="@+id/textView1"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:ellipsize="middle" 
-        android:singleLine="true"
-        android:layout_gravity="center_horizontal"
-        android:text="@string/preparing_media"
-        android:textAppearance="?android:attr/textAppearanceSmall" />
+	<TextView
+		android:id="@+id/textView1"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_below="@+id/progressBar1"
+		android:layout_centerInParent="true"
+		android:text="@string/preparing_media" />
 
-</LinearLayout>
+</RelativeLayout>

BIN
build/android/src/main/res/mipmap/ic_launcher.png


+ 12 - 0
build/android/src/main/res/values-v21/styles.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+	<style name="AppTheme" parent="@android:style/android:Theme.Material.Light.NoActionBar.Fullscreen">
+		<item name="android:windowNoTitle">true</item>
+		<item name="android:windowAnimationStyle">@null</item>
+		<item name="android:background">@drawable/bg</item>
+	</style>
+
+	<style name="Theme.Dialog" parent="@android:style/Theme.Material.Light.Dialog.NoActionBar"/>
+
+</resources>

+ 3 - 3
build/android/src/main/res/values/strings.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-	<string name="preparing_media">Preparing media...</string>
-</resources>
-
+	<string name="preparing_media">Preparing media&#8230;</string>
+	<string name="not_granted">Required permission wasn\'t granted, Minetest can\'t run without it</string>
+</resources>

+ 7 - 6
build/android/src/main/res/values/styles.xml

@@ -1,11 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-	<style name="Theme.Transparent" parent="android:Theme">
-		<item name="android:windowIsTranslucent">true</item>
-		<item name="android:windowBackground">@android:color/transparent</item>
-		<item name="android:windowContentOverlay">@null</item>
+
+	<style name="AppTheme" parent="@android:style/android:Theme.Holo.Light.NoActionBar.Fullscreen">
 		<item name="android:windowNoTitle">true</item>
-		<item name="android:windowIsFloating">true</item>
-		<item name="android:backgroundDimEnabled">false</item>
+		<item name="android:windowAnimationStyle">@null</item>
+		<item name="android:background">@drawable/bg</item>
 	</style>
+
+	<style name="Theme.Dialog" parent="@android:style/android:Theme.Holo.Light.Dialog.NoActionBar"/>
+
 </resources>