aboutsummaryrefslogtreecommitdiff
path: root/android
diff options
context:
space:
mode:
Diffstat (limited to 'android')
-rw-r--r--android/app/build.gradle10
-rw-r--r--android/app/src/main/AndroidManifest.xml6
-rw-r--r--android/app/src/main/java/net/minetest/minetest/CopyZipTask.java82
-rw-r--r--android/app/src/main/java/net/minetest/minetest/GameActivity.java8
-rw-r--r--android/app/src/main/java/net/minetest/minetest/MainActivity.java66
-rw-r--r--android/app/src/main/java/net/minetest/minetest/UnzipService.java186
-rw-r--r--android/app/src/main/java/net/minetest/minetest/Utils.java39
-rw-r--r--android/app/src/main/res/layout/activity_main.xml7
-rw-r--r--android/app/src/main/res/values/strings.xml2
-rw-r--r--android/build.gradle7
-rw-r--r--android/gradle/wrapper/gradle-wrapper.properties3
-rwxr-xr-xandroid/gradlew2
-rw-r--r--android/native/build.gradle54
-rw-r--r--android/native/jni/Android.mk111
-rw-r--r--android/native/jni/Application.mk16
15 files changed, 346 insertions, 253 deletions
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 53fe85910..e8ba95722 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -1,12 +1,12 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 29
+ compileSdkVersion 30
buildToolsVersion '30.0.3'
- ndkVersion '22.0.7026061'
+ ndkVersion "$ndk_version"
defaultConfig {
applicationId 'net.minetest.minetest'
minSdkVersion 16
- targetSdkVersion 29
+ targetSdkVersion 30
versionName "${versionMajor}.${versionMinor}.${versionPatch}"
versionCode project.versionCode
}
@@ -68,7 +68,7 @@ task prepareAssets() {
from "${projRoot}/client/shaders" into "${assetsFolder}/client/shaders"
}
copy {
- from "../native/deps/Android/Irrlicht/shaders" into "${assetsFolder}/client/shaders/Irrlicht"
+ from "../native/deps/armeabi-v7a/Irrlicht/Shaders" into "${assetsFolder}/client/shaders/Irrlicht"
}
copy {
from "${projRoot}/fonts" include "*.ttf" into "${assetsFolder}/fonts"
@@ -112,5 +112,5 @@ android.applicationVariants.all { variant ->
dependencies {
implementation project(':native')
- implementation 'androidx.appcompat:appcompat:1.2.0'
+ implementation 'androidx.appcompat:appcompat:1.3.1'
}
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index fa93e7069..6ea677cb9 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -30,7 +30,8 @@
android:configChanges="orientation|keyboardHidden|navigation|screenSize"
android:maxAspectRatio="3.0"
android:screenOrientation="sensorLandscape"
- android:theme="@style/AppTheme">
+ android:theme="@style/AppTheme"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@@ -44,7 +45,8 @@
android:launchMode="singleTask"
android:maxAspectRatio="3.0"
android:screenOrientation="sensorLandscape"
- android:theme="@style/AppTheme">
+ android:theme="@style/AppTheme"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
diff --git a/android/app/src/main/java/net/minetest/minetest/CopyZipTask.java b/android/app/src/main/java/net/minetest/minetest/CopyZipTask.java
deleted file mode 100644
index 6d4b6ab0f..000000000
--- a/android/app/src/main/java/net/minetest/minetest/CopyZipTask.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-Minetest
-Copyright (C) 2014-2020 MoNTE48, Maksim Gamarnik <MoNTE48@mail.ua>
-Copyright (C) 2014-2020 ubulem, Bektur Mambetov <berkut87@gmail.com>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with this program; if not, write to the Free Software Foundation, Inc.,
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-
-package net.minetest.minetest;
-
-import android.content.Intent;
-import android.os.AsyncTask;
-import android.widget.Toast;
-
-import androidx.appcompat.app.AppCompatActivity;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.ref.WeakReference;
-
-public class CopyZipTask extends AsyncTask<String, Void, String> {
-
- private final WeakReference<AppCompatActivity> activityRef;
-
- CopyZipTask(AppCompatActivity activity) {
- activityRef = new WeakReference<>(activity);
- }
-
- protected String doInBackground(String... params) {
- copyAsset(params[0]);
- return params[0];
- }
-
- @Override
- protected void onPostExecute(String result) {
- startUnzipService(result);
- }
-
- private void copyAsset(String zipName) {
- String filename = zipName.substring(zipName.lastIndexOf("/") + 1);
- try (InputStream in = activityRef.get().getAssets().open(filename);
- OutputStream out = new FileOutputStream(zipName)) {
- copyFile(in, out);
- } catch (IOException e) {
- AppCompatActivity activity = activityRef.get();
- if (activity != null) {
- activity.runOnUiThread(() -> Toast.makeText(activityRef.get(), e.getLocalizedMessage(), Toast.LENGTH_LONG).show());
- }
- cancel(true);
- }
- }
-
- private void copyFile(InputStream in, OutputStream out) throws IOException {
- byte[] buffer = new byte[1024];
- int read;
- while ((read = in.read(buffer)) != -1)
- out.write(buffer, 0, read);
- }
-
- private void startUnzipService(String file) {
- Intent intent = new Intent(activityRef.get(), UnzipService.class);
- intent.putExtra(UnzipService.EXTRA_KEY_IN_FILE, file);
- AppCompatActivity activity = activityRef.get();
- if (activity != null) {
- activity.startService(intent);
- }
- }
-}
diff --git a/android/app/src/main/java/net/minetest/minetest/GameActivity.java b/android/app/src/main/java/net/minetest/minetest/GameActivity.java
index bdf764138..46fc9b1de 100644
--- a/android/app/src/main/java/net/minetest/minetest/GameActivity.java
+++ b/android/app/src/main/java/net/minetest/minetest/GameActivity.java
@@ -171,4 +171,12 @@ public class GameActivity extends NativeActivity {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(browserIntent);
}
+
+ public String getUserDataPath() {
+ return Utils.getUserDataDirectory(this).getAbsolutePath();
+ }
+
+ public String getCachePath() {
+ return Utils.getCacheDirectory(this).getAbsolutePath();
+ }
}
diff --git a/android/app/src/main/java/net/minetest/minetest/MainActivity.java b/android/app/src/main/java/net/minetest/minetest/MainActivity.java
index 2aa50d9ad..b6567b4b7 100644
--- a/android/app/src/main/java/net/minetest/minetest/MainActivity.java
+++ b/android/app/src/main/java/net/minetest/minetest/MainActivity.java
@@ -29,12 +29,14 @@ import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
+import android.os.Environment;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
@@ -43,11 +45,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import static net.minetest.minetest.UnzipService.ACTION_FAILURE;
-import static net.minetest.minetest.UnzipService.ACTION_PROGRESS;
-import static net.minetest.minetest.UnzipService.ACTION_UPDATE;
-import static net.minetest.minetest.UnzipService.FAILURE;
-import static net.minetest.minetest.UnzipService.SUCCESS;
+import static net.minetest.minetest.UnzipService.*;
public class MainActivity extends AppCompatActivity {
private final static int versionCode = BuildConfig.VERSION_CODE;
@@ -56,26 +54,40 @@ public class MainActivity extends AppCompatActivity {
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE};
private static final String SETTINGS = "MinetestSettings";
private static final String TAG_VERSION_CODE = "versionCode";
+
private ProgressBar mProgressBar;
private TextView mTextView;
private SharedPreferences sharedPreferences;
+
private final BroadcastReceiver myReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int progress = 0;
- if (intent != null)
+ @StringRes int message = 0;
+ if (intent != null) {
progress = intent.getIntExtra(ACTION_PROGRESS, 0);
- if (progress >= 0) {
+ message = intent.getIntExtra(ACTION_PROGRESS_MESSAGE, 0);
+ }
+
+ if (progress == FAILURE) {
+ Toast.makeText(MainActivity.this, intent.getStringExtra(ACTION_FAILURE), Toast.LENGTH_LONG).show();
+ finish();
+ } else if (progress == SUCCESS) {
+ startNative();
+ } else {
if (mProgressBar != null) {
mProgressBar.setVisibility(View.VISIBLE);
- mProgressBar.setProgress(progress);
+ if (progress == INDETERMINATE) {
+ mProgressBar.setIndeterminate(true);
+ } else {
+ mProgressBar.setIndeterminate(false);
+ mProgressBar.setProgress(progress);
+ }
}
mTextView.setVisibility(View.VISIBLE);
- } else if (progress == FAILURE) {
- Toast.makeText(MainActivity.this, intent.getStringExtra(ACTION_FAILURE), Toast.LENGTH_LONG).show();
- finish();
- } else if (progress == SUCCESS)
- startNative();
+ if (message != 0)
+ mTextView.setText(message);
+ }
}
};
@@ -88,7 +100,9 @@ public class MainActivity extends AppCompatActivity {
mProgressBar = findViewById(R.id.progressBar);
mTextView = findViewById(R.id.textView);
sharedPreferences = getSharedPreferences(SETTINGS, Context.MODE_PRIVATE);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
+ Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
checkPermission();
else
checkAppVersion();
@@ -120,6 +134,7 @@ public class MainActivity extends AppCompatActivity {
if (grantResult != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, R.string.not_granted, Toast.LENGTH_LONG).show();
finish();
+ return;
}
}
checkAppVersion();
@@ -127,10 +142,27 @@ public class MainActivity extends AppCompatActivity {
}
private void checkAppVersion() {
- if (sharedPreferences.getInt(TAG_VERSION_CODE, 0) == versionCode)
+ if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ Toast.makeText(this, R.string.no_external_storage, Toast.LENGTH_LONG).show();
+ finish();
+ return;
+ }
+
+ if (UnzipService.getIsRunning()) {
+ mProgressBar.setVisibility(View.VISIBLE);
+ mProgressBar.setIndeterminate(true);
+ mTextView.setVisibility(View.VISIBLE);
+ } else if (sharedPreferences.getInt(TAG_VERSION_CODE, 0) == versionCode &&
+ Utils.isInstallValid(this)) {
startNative();
- else
- new CopyZipTask(this).execute(getCacheDir() + "/Minetest.zip");
+ } else {
+ mProgressBar.setVisibility(View.VISIBLE);
+ mProgressBar.setIndeterminate(true);
+ mTextView.setVisibility(View.VISIBLE);
+
+ Intent intent = new Intent(this, UnzipService.class);
+ startService(intent);
+ }
}
private void startNative() {
diff --git a/android/app/src/main/java/net/minetest/minetest/UnzipService.java b/android/app/src/main/java/net/minetest/minetest/UnzipService.java
index b69f7f36e..a61a49139 100644
--- a/android/app/src/main/java/net/minetest/minetest/UnzipService.java
+++ b/android/app/src/main/java/net/minetest/minetest/UnzipService.java
@@ -24,16 +24,22 @@ import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Environment;
-import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.StringRes;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -42,32 +48,61 @@ import java.util.zip.ZipInputStream;
public class UnzipService extends IntentService {
public static final String ACTION_UPDATE = "net.minetest.minetest.UPDATE";
public static final String ACTION_PROGRESS = "net.minetest.minetest.PROGRESS";
+ public static final String ACTION_PROGRESS_MESSAGE = "net.minetest.minetest.PROGRESS_MESSAGE";
public static final String ACTION_FAILURE = "net.minetest.minetest.FAILURE";
- public static final String EXTRA_KEY_IN_FILE = "file";
public static final int SUCCESS = -1;
public static final int FAILURE = -2;
+ public static final int INDETERMINATE = -3;
private final int id = 1;
private NotificationManager mNotifyManager;
private boolean isSuccess = true;
private String failureMessage;
- public UnzipService() {
- super("net.minetest.minetest.UnzipService");
+ private static boolean isRunning = false;
+ public static synchronized boolean getIsRunning() {
+ return isRunning;
+ }
+ private static synchronized void setIsRunning(boolean v) {
+ isRunning = v;
}
- private void isDir(String dir, String location) {
- File f = new File(location, dir);
- if (!f.isDirectory())
- f.mkdirs();
+ public UnzipService() {
+ super("net.minetest.minetest.UnzipService");
}
@Override
protected void onHandleIntent(Intent intent) {
- createNotification();
- unzip(intent);
+ Notification.Builder notificationBuilder = createNotification();
+ final File zipFile = new File(getCacheDir(), "Minetest.zip");
+ try {
+ setIsRunning(true);
+ File userDataDirectory = Utils.getUserDataDirectory(this);
+ if (userDataDirectory == null) {
+ throw new IOException("Unable to find user data directory");
+ }
+
+ try (InputStream in = this.getAssets().open(zipFile.getName())) {
+ try (OutputStream out = new FileOutputStream(zipFile)) {
+ int readLen;
+ byte[] readBuffer = new byte[16384];
+ while ((readLen = in.read(readBuffer)) != -1) {
+ out.write(readBuffer, 0, readLen);
+ }
+ }
+ }
+
+ migrate(notificationBuilder, userDataDirectory);
+ unzip(notificationBuilder, zipFile, userDataDirectory);
+ } catch (IOException e) {
+ isSuccess = false;
+ failureMessage = e.getLocalizedMessage();
+ } finally {
+ setIsRunning(false);
+ zipFile.delete();
+ }
}
- private void createNotification() {
+ private Notification.Builder createNotification() {
String name = "net.minetest.minetest";
String channelId = "Minetest channel";
String description = "notifications from Minetest";
@@ -92,66 +127,133 @@ public class UnzipService extends IntentService {
} else {
builder = new Notification.Builder(this);
}
+
+ Intent notificationIntent = new Intent(this, MainActivity.class);
+ notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
+ | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ PendingIntent intent = PendingIntent.getActivity(this, 0,
+ notificationIntent, 0);
+
builder.setContentTitle(getString(R.string.notification_title))
.setSmallIcon(R.mipmap.ic_launcher)
- .setContentText(getString(R.string.notification_description));
+ .setContentText(getString(R.string.notification_description))
+ .setContentIntent(intent)
+ .setOngoing(true)
+ .setProgress(0, 0, true);
+
mNotifyManager.notify(id, builder.build());
+ return builder;
}
- private void unzip(Intent intent) {
- String zip = intent.getStringExtra(EXTRA_KEY_IN_FILE);
- isDir("Minetest", Environment.getExternalStorageDirectory().toString());
- String location = Environment.getExternalStorageDirectory() + File.separator + "Minetest" + File.separator;
+ private void unzip(Notification.Builder notificationBuilder, File zipFile, File userDataDirectory) throws IOException {
int per = 0;
- int size = getSummarySize(zip);
- File zipFile = new File(zip);
+
+ int size;
+ try (ZipFile zipSize = new ZipFile(zipFile)) {
+ size = zipSize.size();
+ }
+
int readLen;
- byte[] readBuffer = new byte[8192];
+ byte[] readBuffer = new byte[16384];
try (FileInputStream fileInputStream = new FileInputStream(zipFile);
ZipInputStream zipInputStream = new ZipInputStream(fileInputStream)) {
ZipEntry ze;
while ((ze = zipInputStream.getNextEntry()) != null) {
if (ze.isDirectory()) {
++per;
- isDir(ze.getName(), location);
- } else {
- publishProgress(100 * ++per / size);
- try (OutputStream outputStream = new FileOutputStream(location + ze.getName())) {
- while ((readLen = zipInputStream.read(readBuffer)) != -1) {
- outputStream.write(readBuffer, 0, readLen);
- }
+ Utils.createDirs(userDataDirectory, ze.getName());
+ continue;
+ }
+ publishProgress(notificationBuilder, R.string.loading, 100 * ++per / size);
+ try (OutputStream outputStream = new FileOutputStream(
+ new File(userDataDirectory, ze.getName()))) {
+ while ((readLen = zipInputStream.read(readBuffer)) != -1) {
+ outputStream.write(readBuffer, 0, readLen);
}
}
- zipFile.delete();
}
- } catch (IOException e) {
- isSuccess = false;
- failureMessage = e.getLocalizedMessage();
}
}
- private void publishProgress(int progress) {
+ void moveFileOrDir(@NonNull File src, @NonNull File dst) throws IOException {
+ try {
+ Process p = new ProcessBuilder("/system/bin/mv",
+ src.getAbsolutePath(), dst.getAbsolutePath()).start();
+ int exitcode = p.waitFor();
+ if (exitcode != 0)
+ throw new IOException("Move failed with exit code " + exitcode);
+ } catch (InterruptedException e) {
+ throw new IOException("Move operation interrupted");
+ }
+ }
+
+ boolean recursivelyDeleteDirectory(@NonNull File loc) {
+ try {
+ Process p = new ProcessBuilder("/system/bin/rm", "-rf",
+ loc.getAbsolutePath()).start();
+ return p.waitFor() == 0;
+ } catch (IOException | InterruptedException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Migrates user data from deprecated external storage to app scoped storage
+ */
+ private void migrate(Notification.Builder notificationBuilder, File newLocation) throws IOException {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ return;
+ }
+
+ File oldLocation = new File(Environment.getExternalStorageDirectory(), "Minetest");
+ if (!oldLocation.isDirectory())
+ return;
+
+ publishProgress(notificationBuilder, R.string.migrating, 0);
+ newLocation.mkdir();
+
+ String[] dirs = new String[] { "worlds", "games", "mods", "textures", "client" };
+ for (int i = 0; i < dirs.length; i++) {
+ publishProgress(notificationBuilder, R.string.migrating, 100 * i / dirs.length);
+ File dir = new File(oldLocation, dirs[i]), dir2 = new File(newLocation, dirs[i]);
+ if (dir.isDirectory() && !dir2.isDirectory()) {
+ moveFileOrDir(dir, dir2);
+ }
+ }
+
+ for (String filename : new String[] { "minetest.conf" }) {
+ File file = new File(oldLocation, filename), file2 = new File(newLocation, filename);
+ if (file.isFile() && !file2.isFile()) {
+ moveFileOrDir(file, file2);
+ }
+ }
+
+ recursivelyDeleteDirectory(oldLocation);
+ }
+
+ private void publishProgress(@Nullable Notification.Builder notificationBuilder, @StringRes int message, int progress) {
Intent intentUpdate = new Intent(ACTION_UPDATE);
intentUpdate.putExtra(ACTION_PROGRESS, progress);
- if (!isSuccess) intentUpdate.putExtra(ACTION_FAILURE, failureMessage);
+ intentUpdate.putExtra(ACTION_PROGRESS_MESSAGE, message);
+ if (!isSuccess)
+ intentUpdate.putExtra(ACTION_FAILURE, failureMessage);
sendBroadcast(intentUpdate);
- }
- private int getSummarySize(String zip) {
- int size = 0;
- try {
- ZipFile zipSize = new ZipFile(zip);
- size += zipSize.size();
- } catch (IOException e) {
- Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
+ if (notificationBuilder != null) {
+ notificationBuilder.setContentText(getString(message));
+ if (progress == INDETERMINATE) {
+ notificationBuilder.setProgress(100, 50, true);
+ } else {
+ notificationBuilder.setProgress(100, progress, false);
+ }
+ mNotifyManager.notify(id, notificationBuilder.build());
}
- return size;
}
@Override
public void onDestroy() {
super.onDestroy();
mNotifyManager.cancel(id);
- publishProgress(isSuccess ? SUCCESS : FAILURE);
+ publishProgress(null, R.string.loading, isSuccess ? SUCCESS : FAILURE);
}
}
diff --git a/android/app/src/main/java/net/minetest/minetest/Utils.java b/android/app/src/main/java/net/minetest/minetest/Utils.java
new file mode 100644
index 000000000..b2553c844
--- /dev/null
+++ b/android/app/src/main/java/net/minetest/minetest/Utils.java
@@ -0,0 +1,39 @@
+package net.minetest.minetest;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import java.io.File;
+
+public class Utils {
+ public static @NonNull File createDirs(File root, String dir) {
+ File f = new File(root, dir);
+ if (!f.isDirectory())
+ f.mkdirs();
+
+ return f;
+ }
+
+ public static @Nullable File getUserDataDirectory(Context context) {
+ File extDir = context.getExternalFilesDir(null);
+ if (extDir == null) {
+ return null;
+ }
+
+ return createDirs(extDir, "Minetest");
+ }
+
+ public static @Nullable File getCacheDirectory(Context context) {
+ return context.getCacheDir();
+ }
+
+ public static boolean isInstallValid(Context context) {
+ File userDataDirectory = getUserDataDirectory(context);
+ return userDataDirectory != null && userDataDirectory.isDirectory() &&
+ new File(userDataDirectory, "games").isDirectory() &&
+ new File(userDataDirectory, "builtin").isDirectory() &&
+ new File(userDataDirectory, "client").isDirectory() &&
+ new File(userDataDirectory, "textures").isDirectory();
+ }
+}
diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/app/src/main/res/layout/activity_main.xml
index e6f461f14..93508c3cb 100644
--- a/android/app/src/main/res/layout/activity_main.xml
+++ b/android/app/src/main/res/layout/activity_main.xml
@@ -1,4 +1,5 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -14,7 +15,8 @@
android:layout_marginRight="90dp"
android:indeterminate="false"
android:max="100"
- android:visibility="gone" />
+ android:visibility="gone"
+ tools:visibility="visible" />
<TextView
android:id="@+id/textView"
@@ -25,6 +27,7 @@
android:background="@android:color/transparent"
android:text="@string/loading"
android:textColor="#FEFEFE"
- android:visibility="gone" />
+ android:visibility="gone"
+ tools:visibility="visible" />
</RelativeLayout>
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index 85238117f..99f948c99 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -3,9 +3,11 @@
<string name="label">Minetest</string>
<string name="loading">Loading&#8230;</string>
+ <string name="migrating">Migrating save data from old install&#8230; (this may take a while)</string>
<string name="not_granted">Required permission wasn\'t granted, Minetest can\'t run without it</string>
<string name="notification_title">Loading Minetest</string>
<string name="notification_description">Less than 1 minute&#8230;</string>
<string name="ime_dialog_done">Done</string>
+ <string name="no_external_storage">External storage isn\'t available. If you use an SDCard, please reinsert it. Otherwise, try restarting your phone or contacting the Minetest developers</string>
</resources>
diff --git a/android/build.gradle b/android/build.gradle
index 3ba51a4bb..f861ba702 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,21 +1,22 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
project.ext.set("versionMajor", 5) // Version Major
-project.ext.set("versionMinor", 5) // Version Minor
+project.ext.set("versionMinor", 6) // Version Minor
project.ext.set("versionPatch", 0) // Version Patch
project.ext.set("versionExtra", "-dev") // Version Extra
-project.ext.set("versionCode", 32) // Android Version Code
+project.ext.set("versionCode", 38) // Android Version Code
// NOTE: +2 after each release!
// +1 for ARM and +1 for ARM64 APK's, because
// each APK must have a larger `versionCode` than the previous
buildscript {
+ ext.ndk_version = '23.0.7599858'
repositories {
google()
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.1.1'
+ classpath 'com.android.tools.build:gradle:7.0.3'
classpath 'de.undercouch:gradle-download-task:4.1.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index 7fd9307d7..8ad73a75c 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Fri Jan 08 17:52:00 UTC 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
diff --git a/android/gradlew b/android/gradlew
index 83f2acfdc..25e0c1148 100755
--- a/android/gradlew
+++ b/android/gradlew
@@ -98,7 +98,7 @@ location of your Java installation."
fi
else
JAVACMD="java"
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ command -v java >/dev/null || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
diff --git a/android/native/build.gradle b/android/native/build.gradle
index 8ea6347b3..2ddc77135 100644
--- a/android/native/build.gradle
+++ b/android/native/build.gradle
@@ -2,12 +2,12 @@ apply plugin: 'com.android.library'
apply plugin: 'de.undercouch.download'
android {
- compileSdkVersion 29
+ compileSdkVersion 30
buildToolsVersion '30.0.3'
- ndkVersion '22.0.7026061'
+ ndkVersion "$ndk_version"
defaultConfig {
minSdkVersion 16
- targetSdkVersion 29
+ targetSdkVersion 30
externalNativeBuild {
ndkBuild {
arguments '-j' + Runtime.getRuntime().availableProcessors(),
@@ -41,58 +41,28 @@ android {
arguments 'NDEBUG=1'
}
}
+
+ ndk {
+ debugSymbolLevel 'SYMBOL_TABLE'
+ }
}
}
}
// get precompiled deps
-def folder = 'minetest_android_deps_binaries'
-
task downloadDeps(type: Download) {
- src 'https://github.com/minetest/' + folder + '/archive/master.zip'
+ src 'https://github.com/minetest/minetest_android_deps/releases/download/latest/deps.zip'
dest new File(buildDir, 'deps.zip')
overwrite false
}
task getDeps(dependsOn: downloadDeps, type: Copy) {
- def deps = file('deps')
- def f = file("$buildDir/" + folder + "-master")
-
- if (!deps.exists() && !f.exists()) {
+ def deps = new File(buildDir.parent, 'deps')
+ if (!deps.exists()) {
+ deps.mkdir()
from zipTree(downloadDeps.dest)
- into buildDir
- }
-
- doLast {
- if (!deps.exists()) {
- file(f).renameTo(file(deps))
- }
- }
-}
-
-// get sqlite
-def sqlite_ver = '3340000'
-task downloadSqlite(dependsOn: getDeps, type: Download) {
- src 'https://www.sqlite.org/2020/sqlite-amalgamation-' + sqlite_ver + '.zip'
- dest new File(buildDir, 'sqlite.zip')
- overwrite false
-}
-
-task getSqlite(dependsOn: downloadSqlite, type: Copy) {
- def sqlite = file('deps/Android/sqlite')
- def f = file("$buildDir/sqlite-amalgamation-" + sqlite_ver)
-
- if (!sqlite.exists() && !f.exists()) {
- from zipTree(downloadSqlite.dest)
- into buildDir
- }
-
- doLast {
- if (!sqlite.exists()) {
- file(f).renameTo(file(sqlite))
- }
+ into deps
}
}
preBuild.dependsOn getDeps
-preBuild.dependsOn getSqlite
diff --git a/android/native/jni/Android.mk b/android/native/jni/Android.mk
index 26e9b058b..f8ca74d3c 100644
--- a/android/native/jni/Android.mk
+++ b/android/native/jni/Android.mk
@@ -4,62 +4,82 @@ LOCAL_PATH := $(call my-dir)/..
include $(CLEAR_VARS)
LOCAL_MODULE := Curl
-LOCAL_SRC_FILES := deps/Android/Curl/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libcurl.a
+LOCAL_SRC_FILES := deps/$(APP_ABI)/Curl/libcurl.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
-LOCAL_MODULE := Freetype
-LOCAL_SRC_FILES := deps/Android/Freetype/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libfreetype.a
+LOCAL_MODULE := libmbedcrypto
+LOCAL_SRC_FILES := deps/$(APP_ABI)/Curl/libmbedcrypto.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
-LOCAL_MODULE := Irrlicht
-LOCAL_SRC_FILES := deps/Android/Irrlicht/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libIrrlichtMt.a
+LOCAL_MODULE := libmbedtls
+LOCAL_SRC_FILES := deps/$(APP_ABI)/Curl/libmbedtls.a
include $(PREBUILT_STATIC_LIBRARY)
-#include $(CLEAR_VARS)
-#LOCAL_MODULE := LevelDB
-#LOCAL_SRC_FILES := deps/Android/LevelDB/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libleveldb.a
-#include $(PREBUILT_STATIC_LIBRARY)
+include $(CLEAR_VARS)
+LOCAL_MODULE := libmbedx509
+LOCAL_SRC_FILES := deps/$(APP_ABI)/Curl/libmbedx509.a
+include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
-LOCAL_MODULE := LuaJIT
-LOCAL_SRC_FILES := deps/Android/LuaJIT/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libluajit.a
+LOCAL_MODULE := Freetype
+LOCAL_SRC_FILES := deps/$(APP_ABI)/Freetype/libfreetype.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
-LOCAL_MODULE := mbedTLS
-LOCAL_SRC_FILES := deps/Android/mbedTLS/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libmbedtls.a
+LOCAL_MODULE := Iconv
+LOCAL_SRC_FILES := deps/$(APP_ABI)/Iconv/libiconv.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
-LOCAL_MODULE := mbedx509
-LOCAL_SRC_FILES := deps/Android/mbedTLS/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libmbedx509.a
+LOCAL_MODULE := libcharset
+LOCAL_SRC_FILES := deps/$(APP_ABI)/Iconv/libcharset.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
-LOCAL_MODULE := mbedcrypto
-LOCAL_SRC_FILES := deps/Android/mbedTLS/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libmbedcrypto.a
+LOCAL_MODULE := Irrlicht
+LOCAL_SRC_FILES := deps/$(APP_ABI)/Irrlicht/libIrrlichtMt.a
+include $(PREBUILT_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := LuaJIT
+LOCAL_SRC_FILES := deps/$(APP_ABI)/LuaJIT/libluajit.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OpenAL
-LOCAL_SRC_FILES := deps/Android/OpenAL-Soft/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libopenal.a
+LOCAL_SRC_FILES := deps/$(APP_ABI)/OpenAL-Soft/libopenal.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
-LOCAL_MODULE := GetText
-LOCAL_SRC_FILES := deps/Android/GetText/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libintl.a
+LOCAL_MODULE := Gettext
+LOCAL_SRC_FILES := deps/$(APP_ABI)/Gettext/libintl.a
+include $(PREBUILT_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := SQLite3
+LOCAL_SRC_FILES := deps/$(APP_ABI)/SQLite/libsqlite3.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := Vorbis
-LOCAL_SRC_FILES := deps/Android/Vorbis/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libvorbis.a
+LOCAL_SRC_FILES := deps/$(APP_ABI)/Vorbis/libvorbis.a
+include $(PREBUILT_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libvorbisfile
+LOCAL_SRC_FILES := deps/$(APP_ABI)/Vorbis/libvorbisfile.a
+include $(PREBUILT_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libogg
+LOCAL_SRC_FILES := deps/$(APP_ABI)/Vorbis/libogg.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := Zstd
-LOCAL_SRC_FILES := deps/Android/Zstd/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libzstd.a
+LOCAL_SRC_FILES := deps/$(APP_ABI)/Zstd/libzstd.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -71,7 +91,6 @@ LOCAL_CFLAGS += \
-DENABLE_GLES=1 \
-DUSE_CURL=1 \
-DUSE_SOUND=1 \
- -DUSE_FREETYPE=1 \
-DUSE_LEVELDB=0 \
-DUSE_LUAJIT=1 \
-DUSE_GETTEXT=1 \
@@ -96,18 +115,16 @@ LOCAL_C_INCLUDES := \
../../src/script \
../../lib/gmp \
../../lib/jsoncpp \
- deps/Android/Curl/include \
- deps/Android/Freetype/include \
- deps/Android/Irrlicht/include \
- deps/Android/LevelDB/include \
- deps/Android/GetText/include \
- deps/Android/libiconv/include \
- deps/Android/libiconv/libcharset/include \
- deps/Android/LuaJIT/src \
- deps/Android/OpenAL-Soft/include \
- deps/Android/sqlite \
- deps/Android/Vorbis/include \
- deps/Android/Zstd/include
+ deps/$(APP_ABI)/Curl/include \
+ deps/$(APP_ABI)/Freetype/include/freetype2 \
+ deps/$(APP_ABI)/Irrlicht/include \
+ deps/$(APP_ABI)/Gettext/include \
+ deps/$(APP_ABI)/Iconv/include \
+ deps/$(APP_ABI)/LuaJIT/include \
+ deps/$(APP_ABI)/OpenAL-Soft/include \
+ deps/$(APP_ABI)/SQLite/include \
+ deps/$(APP_ABI)/Vorbis/include \
+ deps/$(APP_ABI)/Zstd/include
LOCAL_SRC_FILES := \
$(wildcard ../../src/client/*.cpp) \
@@ -190,24 +207,24 @@ LOCAL_SRC_FILES := \
../../src/voxel.cpp \
../../src/voxelalgorithms.cpp
-# LevelDB backend is disabled
-# ../../src/database/database-leveldb.cpp
-
# GMP
LOCAL_SRC_FILES += ../../lib/gmp/mini-gmp.c
# JSONCPP
LOCAL_SRC_FILES += ../../lib/jsoncpp/jsoncpp.cpp
-# iconv
-LOCAL_SRC_FILES += \
- deps/Android/libiconv/lib/iconv.c \
- deps/Android/libiconv/libcharset/lib/localcharset.c
-
-# SQLite3
-LOCAL_SRC_FILES += deps/Android/sqlite/sqlite3.c
-
-LOCAL_STATIC_LIBRARIES += Curl Freetype Irrlicht OpenAL mbedTLS mbedx509 mbedcrypto Vorbis LuaJIT GetText Zstd android_native_app_glue $(PROFILER_LIBS) #LevelDB
+LOCAL_STATIC_LIBRARIES += \
+ Curl libmbedcrypto libmbedtls libmbedx509 \
+ Freetype \
+ Iconv libcharset \
+ Irrlicht \
+ LuaJIT \
+ OpenAL \
+ Gettext \
+ SQLite3 \
+ Vorbis libvorbisfile libogg \
+ Zstd
+LOCAL_STATIC_LIBRARIES += android_native_app_glue $(PROFILER_LIBS)
LOCAL_LDLIBS := -lEGL -lGLESv1_CM -lGLESv2 -landroid -lOpenSLES
diff --git a/android/native/jni/Application.mk b/android/native/jni/Application.mk
index 82f0148f0..9d9596137 100644
--- a/android/native/jni/Application.mk
+++ b/android/native/jni/Application.mk
@@ -5,22 +5,22 @@ NDK_TOOLCHAIN_VERSION := clang
APP_SHORT_COMMANDS := true
APP_MODULES := Minetest
-APP_CPPFLAGS := -Ofast -fvisibility=hidden -fexceptions -Wno-deprecated-declarations -Wno-extra-tokens
+APP_CPPFLAGS := -O2 -fvisibility=hidden
ifeq ($(APP_ABI),armeabi-v7a)
-APP_CPPFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb
+APP_CPPFLAGS += -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb
endif
-#ifeq ($(APP_ABI),x86)
-#APP_CPPFLAGS += -march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32 -funroll-loops
-#endif
+ifeq ($(APP_ABI),x86)
+APP_CPPFLAGS += -mssse3 -mfpmath=sse -funroll-loops
+endif
ifndef NDEBUG
-APP_CPPFLAGS := -g -D_DEBUG -O0 -fno-omit-frame-pointer -fexceptions
+APP_CPPFLAGS := -g -Og -fno-omit-frame-pointer
endif
-APP_CFLAGS := $(APP_CPPFLAGS) -Wno-parentheses-equality #-Werror=shorten-64-to-32
-APP_CXXFLAGS := $(APP_CPPFLAGS) -frtti -std=gnu++17
+APP_CFLAGS := $(APP_CPPFLAGS) -Wno-inconsistent-missing-override -Wno-parentheses-equality
+APP_CXXFLAGS := $(APP_CPPFLAGS) -fexceptions -frtti -std=gnu++14
APP_LDFLAGS := -Wl,--no-warn-mismatch,--gc-sections,--icf=safe
ifeq ($(APP_ABI),arm64-v8a)