Backport MultiCraft Android Java part
@ -1,18 +1,23 @@
|
||||
apply plugin: 'com.android.application'
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion '29.0.3'
|
||||
ndkVersion '21.1.6352462'
|
||||
buildToolsVersion '30.0.3'
|
||||
ndkVersion '22.0.7026061'
|
||||
defaultConfig {
|
||||
applicationId 'net.minetest.minetest'
|
||||
applicationId 'com.multicraft.game'
|
||||
minSdkVersion 16
|
||||
//noinspection OldTargetApi
|
||||
targetSdkVersion 29
|
||||
versionName "${versionMajor}.${versionMinor}.${versionPatch}"
|
||||
versionCode project.versionCode
|
||||
multiDexEnabled true
|
||||
}
|
||||
|
||||
// load properties
|
||||
Properties props = new Properties()
|
||||
props.load(new FileInputStream(file('../local.properties')))
|
||||
def propfile = file('../local.properties')
|
||||
if (propfile.exists())
|
||||
props.load(new FileInputStream(propfile))
|
||||
|
||||
if (props.getProperty('keystore') != null) {
|
||||
signingConfigs {
|
||||
@ -26,9 +31,14 @@ android {
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
shrinkResources true
|
||||
minifyEnabled true
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
debug {
|
||||
debuggable true
|
||||
minifyEnabled false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,55 +57,75 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
task prepareAssets() {
|
||||
def assetsFolder = "build/assets"
|
||||
import com.android.build.OutputFile
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
|
||||
task prepareAssetsFiles() {
|
||||
def assetsFolder = "build/assets/Files"
|
||||
def projRoot = "../../.."
|
||||
def gameToCopy = "minetest_game"
|
||||
|
||||
copy {
|
||||
from "${projRoot}/minetest.conf.example", "${projRoot}/README.md" into assetsFolder
|
||||
from "${projRoot}/builtin" into "${assetsFolder}/builtin" exclude '*.txt'
|
||||
}
|
||||
copy {
|
||||
from "${projRoot}/doc/lgpl-2.1.txt" into "${assetsFolder}"
|
||||
}
|
||||
copy {
|
||||
from "${projRoot}/builtin" into "${assetsFolder}/builtin"
|
||||
}
|
||||
/*copy {
|
||||
// ToDo: fix Minetest shaders that currently don't work with OpenGL ES
|
||||
from "${projRoot}/client/shaders" into "${assetsFolder}/client/shaders"
|
||||
}*/
|
||||
}
|
||||
copy {
|
||||
from "../native/deps/Android/Irrlicht/shaders" into "${assetsFolder}/client/shaders/Irrlicht"
|
||||
}
|
||||
copy {
|
||||
from "${projRoot}/fonts" include "*.ttf" into "${assetsFolder}/fonts"
|
||||
from "${projRoot}/fonts/Retron2000.ttf" into "${assetsFolder}/fonts"
|
||||
}
|
||||
fileTree("${projRoot}/po").include("**/*.po").forEach { poFile ->
|
||||
def moPath = "${assetsFolder}/locale/${poFile.parentFile.name}/LC_MESSAGES/"
|
||||
file(moPath).mkdirs()
|
||||
if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
exec {
|
||||
commandLine 'msgfmt', '-o', "${moPath}/minetest.mo", poFile
|
||||
}
|
||||
}
|
||||
}
|
||||
copy {
|
||||
from "${projRoot}/games/${gameToCopy}" into "${assetsFolder}/games/${gameToCopy}"
|
||||
}
|
||||
/*copy {
|
||||
// ToDo: fix broken locales
|
||||
from "${projRoot}/po" into "${assetsFolder}/po"
|
||||
}*/
|
||||
copy {
|
||||
from "${projRoot}/textures" into "${assetsFolder}/textures"
|
||||
from "${projRoot}/textures" into "${assetsFolder}/textures" exclude '*.txt'
|
||||
}
|
||||
|
||||
file("${assetsFolder}/.nomedia").text = "";
|
||||
task zipAssetsFiles(type: Zip) {
|
||||
archiveFileName = "Files.zip"
|
||||
destinationDirectory = file("src/main/assets/data")
|
||||
|
||||
task zipAssets(type: Zip) {
|
||||
archiveName "Minetest.zip"
|
||||
from "${assetsFolder}"
|
||||
destinationDir file("src/main/assets")
|
||||
}
|
||||
}
|
||||
|
||||
preBuild.dependsOn zipAssets
|
||||
task prepareAssetsGames() {
|
||||
def assetsFolder = "build/assets/games"
|
||||
def projRoot = "../../.."
|
||||
def gameToCopy = "default"
|
||||
|
||||
copy {
|
||||
from "${projRoot}/games/${gameToCopy}" into "${assetsFolder}/games/${gameToCopy}"
|
||||
}
|
||||
|
||||
task zipAssetsGames(type: Zip) {
|
||||
archiveFileName = "games.zip"
|
||||
destinationDirectory = file("src/main/assets/data")
|
||||
from "${assetsFolder}"
|
||||
}
|
||||
}
|
||||
|
||||
task zipAssetsWorlds(type: Zip) {
|
||||
archiveFileName = "worlds.zip"
|
||||
destinationDirectory = file("src/main/assets/data")
|
||||
from("../../worlds") {
|
||||
into "worlds"
|
||||
}
|
||||
}
|
||||
|
||||
preBuild.dependsOn zipAssetsFiles
|
||||
preBuild.dependsOn zipAssetsGames
|
||||
preBuild.dependsOn zipAssetsWorlds
|
||||
|
||||
// Map for the version code that gives each ABI a value.
|
||||
import com.android.build.OutputFile
|
||||
|
||||
def abiCodes = ['armeabi-v7a': 0, 'arm64-v8a': 1]
|
||||
android.applicationVariants.all { variant ->
|
||||
variant.outputs.each {
|
||||
@ -106,6 +136,23 @@ android.applicationVariants.all { variant ->
|
||||
}
|
||||
|
||||
dependencies {
|
||||
/* MultiCraft Native */
|
||||
implementation project(':native')
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
|
||||
/* Third-party libraries */
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
implementation 'androidx.preference:preference:1.1.1'
|
||||
implementation 'com.google.android.play:core:1.9.1'
|
||||
implementation 'io.reactivex.rxjava2:rxjava:2.2.20'
|
||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
||||
//noinspection GradleDependency
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.12.12'
|
||||
//noinspection GradleDependency
|
||||
implementation 'commons-io:commons-io:2.5'
|
||||
implementation 'gun0912.ted:tedpermission-rx2:2.2.3'
|
||||
implementation 'com.google.code.gson:gson:2.8.6'
|
||||
|
||||
/* Analytics libraries */
|
||||
//noinspection GradleDynamicVersion
|
||||
/*implementation 'com.bugsnag:bugsnag-android-core:5.+'*/
|
||||
}
|
||||
|
@ -1,24 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="net.minetest.minetest"
|
||||
package="com.multicraft.game"
|
||||
android:installLocation="auto">
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
tools:node="replace" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
|
||||
|
||||
<!--
|
||||
`android:requestLegacyExternalStorage="true"` is workaround for using `/sdcard`
|
||||
instead of the `getFilesDir()` patch for assets. Check link below for more information:
|
||||
https://developer.android.com/training/data-storage/compatibility
|
||||
-->
|
||||
<uses-feature
|
||||
android:name="android.hardware.touchscreen"
|
||||
android:required="false" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.wifi"
|
||||
android:required="false" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.screen.portrait"
|
||||
android:required="false" />
|
||||
|
||||
<supports-screens
|
||||
android:largeScreens="true"
|
||||
android:xlargeScreens="true" />
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:name="com.multicraft.game.MyApplication"
|
||||
android:allowBackup="true"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/label"
|
||||
android:resizeableActivity="false"
|
||||
android:label="@string/app_name"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:resizeableActivity="false"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<meta-data
|
||||
@ -26,7 +45,7 @@
|
||||
android:value="3.0" />
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:name="com.multicraft.game.MainActivity"
|
||||
android:configChanges="orientation|keyboardHidden|navigation|screenSize"
|
||||
android:maxAspectRatio="3.0"
|
||||
android:screenOrientation="sensorLandscape"
|
||||
@ -38,30 +57,27 @@
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".GameActivity"
|
||||
android:name="com.multicraft.game.GameActivity"
|
||||
android:configChanges="orientation|keyboard|keyboardHidden|navigation|screenSize|smallestScreenSize"
|
||||
android:hardwareAccelerated="true"
|
||||
android:launchMode="singleTask"
|
||||
android:maxAspectRatio="3.0"
|
||||
android:screenOrientation="sensorLandscape"
|
||||
android:theme="@style/AppTheme">
|
||||
<meta-data
|
||||
android:name="android.app.lib_name"
|
||||
android:value="MultiCraft" />
|
||||
|
||||
<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=".InputDialogActivity"
|
||||
android:maxAspectRatio="3.0"
|
||||
android:theme="@style/InputTheme" />
|
||||
|
||||
<service
|
||||
android:name=".UnzipService"
|
||||
android:name="com.multicraft.game.UnzipService"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
@ -0,0 +1,18 @@
|
||||
package com.bugsnag.android;
|
||||
|
||||
import android.app.Application;
|
||||
import android.util.Log;
|
||||
|
||||
public class Bugsnag {
|
||||
public static void notify(Throwable e) {
|
||||
Log.getStackTraceString(e);
|
||||
}
|
||||
|
||||
public static void leaveBreadcrumb(String s) {
|
||||
Log.d("Bugsnag", s);
|
||||
}
|
||||
|
||||
public static void start(Application application) {
|
||||
Log.d("Bugsnag", "Bugsnag initialized");
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
MultiCraft
|
||||
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 3.0 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 com.multicraft.game;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import androidx.appcompat.widget.AppCompatEditText;
|
||||
|
||||
public class CustomEditText extends AppCompatEditText {
|
||||
public CustomEditText(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
InputMethodManager mgr = (InputMethodManager)
|
||||
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
mgr.hideSoftInputFromWindow(this.getWindowToken(), 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,315 @@
|
||||
/*
|
||||
MultiCraft
|
||||
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 3.0 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 com.multicraft.game;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.NativeActivity;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.Gravity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.bugsnag.android.Bugsnag;
|
||||
import com.multicraft.game.helpers.PreferencesHelper;
|
||||
import com.multicraft.game.helpers.RateMeHelper;
|
||||
import com.multicraft.game.helpers.Utilities;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONTokener;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
import static android.content.res.Configuration.KEYBOARD_QWERTY;
|
||||
import static com.multicraft.game.helpers.AdManager.initAd;
|
||||
import static com.multicraft.game.helpers.AdManager.setAdsCallback;
|
||||
import static com.multicraft.game.helpers.AdManager.startAd;
|
||||
import static com.multicraft.game.helpers.AdManager.stopAd;
|
||||
import static com.multicraft.game.helpers.Constants.versionCode;
|
||||
import static com.multicraft.game.helpers.PreferencesHelper.IS_ASK_CONSENT;
|
||||
import static com.multicraft.game.helpers.PreferencesHelper.TAG_EXIT_GAME_COUNT;
|
||||
import static com.multicraft.game.helpers.PreferencesHelper.TAG_LAST_RATE_VERSION_CODE;
|
||||
import static com.multicraft.game.helpers.PreferencesHelper.getInstance;
|
||||
import static com.multicraft.game.helpers.Utilities.getIcon;
|
||||
import static com.multicraft.game.helpers.Utilities.makeFullScreen;
|
||||
|
||||
public class GameActivity extends NativeActivity {
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("MultiCraft");
|
||||
} catch (UnsatisfiedLinkError | OutOfMemoryError e) {
|
||||
Bugsnag.notify(e);
|
||||
System.exit(0);
|
||||
} catch (IllegalArgumentException i) {
|
||||
Bugsnag.notify(i);
|
||||
System.exit(0);
|
||||
} catch (Error | Exception e) {
|
||||
Bugsnag.notify(e);
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
private int messageReturnCode = -1;
|
||||
private String messageReturnValue = "";
|
||||
private int height, width;
|
||||
private boolean consent, isMultiPlayer;
|
||||
private PreferencesHelper pf;
|
||||
private Disposable adInitSub, gdprSub;
|
||||
private boolean hasKeyboard;
|
||||
|
||||
public static native void pauseGame();
|
||||
|
||||
public static native void keyboardEvent(boolean keyboard);
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Bundle bundle = getIntent().getExtras();
|
||||
Resources resources = getResources();
|
||||
height = bundle != null ? bundle.getInt("height", 0) : resources.getDisplayMetrics().heightPixels;
|
||||
width = bundle != null ? bundle.getInt("width", 0) : resources.getDisplayMetrics().widthPixels;
|
||||
getWindow().addFlags(LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
hasKeyboard = !(resources.getConfiguration().hardKeyboardHidden == KEYBOARD_QWERTY);
|
||||
keyboardEvent(hasKeyboard);
|
||||
pf = getInstance(this);
|
||||
RateMeHelper.onStart(this);
|
||||
askGdpr();
|
||||
}
|
||||
|
||||
private void subscribeAds() {
|
||||
if (pf.isAdsEnable()) {
|
||||
adInitSub = Completable.fromAction(() -> initAd(this, consent))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(() -> setAdsCallback(this));
|
||||
}
|
||||
}
|
||||
|
||||
// GDPR check
|
||||
private void askGdpr() {
|
||||
if (pf.isAskConsent())
|
||||
isGdprSubject();
|
||||
else {
|
||||
consent = true;
|
||||
subscribeAds();
|
||||
}
|
||||
}
|
||||
|
||||
private void isGdprSubject() {
|
||||
gdprSub = Observable.fromCallable(() -> Utilities.getJson("http://adservice.google.com/getconfig/pubvendors"))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
JSONObject json = new JSONObject(new JSONTokener(result));
|
||||
if (json.getBoolean("is_request_in_eea_or_unknown"))
|
||||
showGdprDialog();
|
||||
else {
|
||||
consent = true;
|
||||
subscribeAds();
|
||||
}
|
||||
},
|
||||
throwable -> {
|
||||
consent = true;
|
||||
subscribeAds();
|
||||
});
|
||||
}
|
||||
|
||||
private void showGdprDialog() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setIcon(getIcon(this));
|
||||
builder.setTitle(getString(R.string.app_name));
|
||||
TextView tv = new TextView(this);
|
||||
tv.setText(R.string.gdpr_main_text);
|
||||
tv.setTypeface(null);
|
||||
tv.setPadding(20, 0, 20, 0);
|
||||
tv.setGravity(Gravity.CENTER);
|
||||
tv.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
builder.setView(tv);
|
||||
builder.setPositiveButton(getString(R.string.gdpr_agree), (dialogInterface, i) -> {
|
||||
dialogInterface.dismiss();
|
||||
pf.saveSettings(IS_ASK_CONSENT, false);
|
||||
consent = true;
|
||||
subscribeAds();
|
||||
});
|
||||
builder.setNegativeButton(getString(R.string.gdpr_disagree), (dialogInterface, i) -> {
|
||||
dialogInterface.dismiss();
|
||||
pf.saveSettings(IS_ASK_CONSENT, false);
|
||||
consent = false;
|
||||
subscribeAds();
|
||||
});
|
||||
builder.setCancelable(false);
|
||||
final AlertDialog dialog = builder.create();
|
||||
if (!isFinishing())
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void checkRateDialog() {
|
||||
if (RateMeHelper.shouldShowRateDialog()) {
|
||||
pf.saveSettings(TAG_LAST_RATE_VERSION_CODE, versionCode);
|
||||
runOnUiThread(() -> RateMeHelper.showRateDialog(this));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
if (hasFocus)
|
||||
makeFullScreen(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
makeFullScreen(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (adInitSub != null) adInitSub.dispose();
|
||||
if (gdprSub != null) gdprSub.dispose();
|
||||
}
|
||||
|
||||
public void showDialog(String acceptButton, String hint, String current, int editType) {
|
||||
runOnUiThread(() -> showDialogUI(hint, current, editType));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
pauseGame();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
boolean statusKeyboard = !(getResources().getConfiguration().hardKeyboardHidden == KEYBOARD_QWERTY);
|
||||
if (hasKeyboard != statusKeyboard) {
|
||||
hasKeyboard = statusKeyboard;
|
||||
keyboardEvent(hasKeyboard);
|
||||
}
|
||||
}
|
||||
|
||||
private void showDialogUI(String hint, String current, int editType) {
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
EditText editText = new CustomEditText(this);
|
||||
builder.setView(editText);
|
||||
AlertDialog alertDialog = builder.create();
|
||||
editText.requestFocus();
|
||||
editText.setHint(hint);
|
||||
editText.setText(current);
|
||||
final InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
|
||||
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,
|
||||
InputMethodManager.HIDE_IMPLICIT_ONLY);
|
||||
if (editType == 1)
|
||||
editText.setInputType(InputType.TYPE_CLASS_TEXT |
|
||||
InputType.TYPE_TEXT_FLAG_MULTI_LINE);
|
||||
else if (editType == 3)
|
||||
editText.setInputType(InputType.TYPE_CLASS_TEXT |
|
||||
InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
||||
else
|
||||
editText.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||
editText.setSelection(editText.getText().length());
|
||||
editText.setOnKeyListener((view, KeyCode, event) -> {
|
||||
if (KeyCode == KeyEvent.KEYCODE_ENTER) {
|
||||
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
|
||||
messageReturnCode = 0;
|
||||
messageReturnValue = editText.getText().toString();
|
||||
alertDialog.dismiss();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
alertDialog.show();
|
||||
alertDialog.setOnCancelListener(dialog -> {
|
||||
getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
|
||||
messageReturnValue = current;
|
||||
messageReturnCode = -1;
|
||||
});
|
||||
}
|
||||
|
||||
public int getDialogState() {
|
||||
return messageReturnCode;
|
||||
}
|
||||
|
||||
public String getDialogValue() {
|
||||
messageReturnCode = -1;
|
||||
return messageReturnValue;
|
||||
}
|
||||
|
||||
public float getDensity() {
|
||||
return getResources().getDisplayMetrics().density;
|
||||
}
|
||||
|
||||
public int getDisplayHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public int getDisplayWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public float getMemoryMax() {
|
||||
ActivityManager actManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
|
||||
ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
|
||||
float memory = 1.0f;
|
||||
if (actManager != null) {
|
||||
actManager.getMemoryInfo(memInfo);
|
||||
memory = memInfo.totalMem * 1.0f / (1024 * 1024 * 1024);
|
||||
memory = Math.round(memory * 100) / 100.0f;
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
public void notifyServerConnect(boolean multiplayer) {
|
||||
isMultiPlayer = multiplayer;
|
||||
if (isMultiPlayer)
|
||||
stopAd();
|
||||
}
|
||||
|
||||
public void notifyExitGame() {
|
||||
pf.saveSettings(TAG_EXIT_GAME_COUNT, pf.getExitGameCount() + 1);
|
||||
if (!isFinishing()) {
|
||||
if (isMultiPlayer) {
|
||||
if (pf.isAdsEnable())
|
||||
startAd(this, false, true);
|
||||
} else
|
||||
checkRateDialog();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
MultiCraft
|
||||
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 3.0 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 com.multicraft.game;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JsonSettings {
|
||||
@SerializedName(value = "version_code")
|
||||
private int versionCode;
|
||||
@SerializedName(value = "version_code_bad")
|
||||
private List<Integer> badVersionCodes;
|
||||
@SerializedName(value = "rate_min_version_code")
|
||||
private int rateMinVersionCode;
|
||||
@SerializedName(value = "package")
|
||||
private String packageName;
|
||||
@SerializedName(value = "content_ru")
|
||||
private String contentRus;
|
||||
@SerializedName(value = "content_en")
|
||||
private String contentEng;
|
||||
@SerializedName(value = "ads_delay")
|
||||
private int adsDelay;
|
||||
@SerializedName(value = "ads_repeat")
|
||||
private int adsRepeat;
|
||||
@SerializedName(value = "ads_enable")
|
||||
private boolean adsEnabled;
|
||||
@SerializedName(value = "review_enable")
|
||||
private boolean reviewEnabled;
|
||||
|
||||
public int getVersionCode() {
|
||||
return versionCode;
|
||||
}
|
||||
|
||||
public List<Integer> getBadVersionCodes() {
|
||||
return badVersionCodes;
|
||||
}
|
||||
|
||||
public int getRateMinVersionCode() {
|
||||
return rateMinVersionCode;
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return packageName;
|
||||
}
|
||||
|
||||
public int getAdsDelay() {
|
||||
return adsDelay;
|
||||
}
|
||||
|
||||
public int getAdsRepeat() {
|
||||
return adsRepeat;
|
||||
}
|
||||
|
||||
public boolean isAdsEnabled() {
|
||||
return adsEnabled;
|
||||
}
|
||||
|
||||
public boolean isReviewEnabled() {
|
||||
return reviewEnabled;
|
||||
}
|
||||
|
||||
public String getContentRus() {
|
||||
return contentRus;
|
||||
}
|
||||
|
||||
public String getContentEng() {
|
||||
return contentEng;
|
||||
}
|
||||
}
|
@ -0,0 +1,468 @@
|
||||
/*
|
||||
MultiCraft
|
||||
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 3.0 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 com.multicraft.game;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.IntentSender;
|
||||
import android.graphics.BlendMode;
|
||||
import android.graphics.BlendModeColorFilter;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.view.Display;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.bugsnag.android.Bugsnag;
|
||||
import com.google.android.play.core.appupdate.AppUpdateInfo;
|
||||
import com.google.android.play.core.appupdate.AppUpdateManager;
|
||||
import com.google.android.play.core.appupdate.AppUpdateManagerFactory;
|
||||
import com.google.android.play.core.install.InstallStateUpdatedListener;
|
||||
import com.google.android.play.core.install.model.AppUpdateType;
|
||||
import com.google.android.play.core.install.model.InstallStatus;
|
||||
import com.google.android.play.core.install.model.UpdateAvailability;
|
||||
import com.google.android.play.core.tasks.Task;
|
||||
import com.multicraft.game.callbacks.CallBackListener;
|
||||
import com.multicraft.game.helpers.PermissionHelper;
|
||||
import com.multicraft.game.helpers.PreferencesHelper;
|
||||
import com.multicraft.game.helpers.Utilities;
|
||||
import com.multicraft.game.helpers.VersionManagerHelper;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
import static android.provider.Settings.ACTION_WIFI_SETTINGS;
|
||||
import static android.provider.Settings.ACTION_WIRELESS_SETTINGS;
|
||||
import static com.multicraft.game.UnzipService.ACTION_FAILURE;
|
||||
import static com.multicraft.game.UnzipService.UNZIP_FAILURE;
|
||||
import static com.multicraft.game.UnzipService.UNZIP_SUCCESS;
|
||||
import static com.multicraft.game.helpers.ApiLevelHelper.isAndroidQ;
|
||||
import static com.multicraft.game.helpers.ApiLevelHelper.isJellyBeanMR1;
|
||||
import static com.multicraft.game.helpers.ApiLevelHelper.isLollipop;
|
||||
import static com.multicraft.game.helpers.ApiLevelHelper.isOreo;
|
||||
import static com.multicraft.game.helpers.Constants.FILES;
|
||||
import static com.multicraft.game.helpers.Constants.GAMES;
|
||||
import static com.multicraft.game.helpers.Constants.NO_SPACE_LEFT;
|
||||
import static com.multicraft.game.helpers.Constants.REQUEST_CONNECTION;
|
||||
import static com.multicraft.game.helpers.Constants.REQUEST_UPDATE;
|
||||
import static com.multicraft.game.helpers.Constants.UPDATE_LINK;
|
||||
import static com.multicraft.game.helpers.Constants.WORLDS;
|
||||
import static com.multicraft.game.helpers.Constants.versionName;
|
||||
import static com.multicraft.game.helpers.PreferencesHelper.TAG_BUILD_NUMBER;
|
||||
import static com.multicraft.game.helpers.PreferencesHelper.TAG_LAUNCH_TIMES;
|
||||
import static com.multicraft.game.helpers.Utilities.addShortcut;
|
||||
import static com.multicraft.game.helpers.Utilities.deleteFiles;
|
||||
import static com.multicraft.game.helpers.Utilities.getIcon;
|
||||
import static com.multicraft.game.helpers.Utilities.getZipsFromAssets;
|
||||
import static com.multicraft.game.helpers.Utilities.makeFullScreen;
|
||||
|
||||
public class MainActivity extends AppCompatActivity implements CallBackListener {
|
||||
private ArrayList<String> zips;
|
||||
private int height, width;
|
||||
private ProgressBar mProgressBar, mProgressBarIndeterminate;
|
||||
private TextView mLoading;
|
||||
private VersionManagerHelper versionManagerHelper = null;
|
||||
private PreferencesHelper pf;
|
||||
private AppUpdateManager appUpdateManager;
|
||||
final InstallStateUpdatedListener listener = state -> {
|
||||
if (state.installStatus() == InstallStatus.DOWNLOADING) {
|
||||
if (mProgressBar != null) {
|
||||
int progress = (int) (state.bytesDownloaded() * 100 / state.totalBytesToDownload());
|
||||
showProgress(R.string.downloading, R.string.downloadingp, progress);
|
||||
}
|
||||
} else if (state.installStatus() == InstallStatus.DOWNLOADED) {
|
||||
appUpdateManager.completeUpdate();
|
||||
}
|
||||
};
|
||||
private Disposable connectionSub, versionManagerSub, cleanSub, copySub;
|
||||
private final BroadcastReceiver myReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
int progress = 0;
|
||||
if (intent != null)
|
||||
progress = intent.getIntExtra(UnzipService.ACTION_PROGRESS, 0);
|
||||
if (progress >= 0) {
|
||||
if (mProgressBar != null) {
|
||||
showProgress(R.string.loading, R.string.loadingp, progress);
|
||||
}
|
||||
} else if (progress == UNZIP_FAILURE) {
|
||||
Toast.makeText(MainActivity.this, intent.getStringExtra(ACTION_FAILURE), Toast.LENGTH_LONG).show();
|
||||
showRestartDialog("");
|
||||
} else if (progress == UNZIP_SUCCESS) {
|
||||
deleteFiles(Arrays.asList(FILES, WORLDS, GAMES), getCacheDir().toString());
|
||||
runGame();
|
||||
}
|
||||
}
|
||||
};
|
||||
private Task<AppUpdateInfo> appUpdateInfoTask;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getWindow().addFlags(LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
setContentView(R.layout.activity_main);
|
||||
pf = PreferencesHelper.getInstance(this);
|
||||
appUpdateManager = AppUpdateManagerFactory.create(this);
|
||||
appUpdateInfoTask = appUpdateManager.getAppUpdateInfo();
|
||||
IntentFilter filter = new IntentFilter(UnzipService.ACTION_UPDATE);
|
||||
registerReceiver(myReceiver, filter);
|
||||
if (!isTaskRoot()) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
addLaunchTimes();
|
||||
PermissionHelper permission = new PermissionHelper(this);
|
||||
permission.setListener(this);
|
||||
permission.askPermissions();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
makeFullScreen(this);
|
||||
appUpdateInfoTask.addOnSuccessListener(appUpdateInfo -> {
|
||||
if (appUpdateInfo.installStatus() == InstallStatus.DOWNLOADED)
|
||||
appUpdateManager.completeUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// Prevent abrupt interruption when copy game files from assets
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (connectionSub != null) connectionSub.dispose();
|
||||
if (versionManagerSub != null) versionManagerSub.dispose();
|
||||
if (cleanSub != null) cleanSub.dispose();
|
||||
if (copySub != null) copySub.dispose();
|
||||
appUpdateManager.unregisterListener(listener);
|
||||
unregisterReceiver(myReceiver);
|
||||
}
|
||||
|
||||
private void addLaunchTimes() {
|
||||
pf.saveSettings(TAG_LAUNCH_TIMES, pf.getLaunchTimes() + 1);
|
||||
}
|
||||
|
||||
// interface
|
||||
private void showProgress(int textMessage, int progressMessage, int progress) {
|
||||
if (mProgressBar.getVisibility() == View.GONE) {
|
||||
updateViews(textMessage, View.VISIBLE, View.GONE, View.VISIBLE);
|
||||
mProgressBar.setProgress(0);
|
||||
} else if (progress > 0) {
|
||||
mLoading.setText(String.format(getResources().getString(progressMessage), progress));
|
||||
mProgressBar.setProgress(progress);
|
||||
// colorize the progress bar
|
||||
Drawable progressDrawable = ((LayerDrawable)
|
||||
mProgressBar.getProgressDrawable()).getDrawable(1);
|
||||
int color = Color.rgb(255 - progress * 2, progress * 2, 25);
|
||||
if (isAndroidQ())
|
||||
progressDrawable.setColorFilter(new BlendModeColorFilter(color, BlendMode.SRC_IN));
|
||||
else
|
||||
progressDrawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
}
|
||||
|
||||
// real screen resolution
|
||||
private void getDefaultResolution() {
|
||||
Display display = getWindowManager().getDefaultDisplay();
|
||||
Point size = new Point();
|
||||
if (isJellyBeanMR1())
|
||||
display.getRealSize(size);
|
||||
else
|
||||
display.getSize(size);
|
||||
height = Math.min(size.x, size.y);
|
||||
width = Math.max(size.x, size.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
if (hasFocus)
|
||||
makeFullScreen(this);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mProgressBar = findViewById(R.id.PB1);
|
||||
mProgressBarIndeterminate = findViewById(R.id.PB2);
|
||||
mLoading = findViewById(R.id.tv_progress);
|
||||
if (!pf.isCreateShortcut() && !isOreo())
|
||||
addShortcut(this);
|
||||
checkAppVersion();
|
||||
}
|
||||
|
||||
void showUpdateDialog() {
|
||||
updateViews(R.string.loading, View.VISIBLE, View.VISIBLE, View.GONE);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setIcon(getIcon(this))
|
||||
.setTitle(R.string.available)
|
||||
.setMessage(Html.fromHtml(
|
||||
versionManagerHelper.getMessage(), null, versionManagerHelper.getCustomTagHandler()))
|
||||
.setPositiveButton(R.string.update, (dialogInterface, i) -> {
|
||||
versionManagerHelper.updateNow(versionManagerHelper.getUpdateUrl());
|
||||
finish();
|
||||
})
|
||||
.setNeutralButton(R.string.later, (dialogInterface, i) -> {
|
||||
versionManagerHelper.remindMeLater();
|
||||
startNative();
|
||||
});
|
||||
builder.setCancelable(false);
|
||||
final AlertDialog dialog = builder.create();
|
||||
if (!isFinishing())
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public void startUpdate() {
|
||||
appUpdateInfoTask.addOnSuccessListener(appUpdateInfo -> {
|
||||
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
|
||||
&& appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
|
||||
try {
|
||||
appUpdateManager.startUpdateFlowForResult(
|
||||
appUpdateInfo, AppUpdateType.FLEXIBLE, this, REQUEST_UPDATE);
|
||||
} catch (IntentSender.SendIntentException e) {
|
||||
//Bugsnag.notify(e);
|
||||
showUpdateDialog();
|
||||
}
|
||||
} else {
|
||||
showUpdateDialog();
|
||||
}
|
||||
});
|
||||
appUpdateInfoTask.addOnFailureListener(e -> {
|
||||
//Bugsnag.notify(e);
|
||||
showUpdateDialog();
|
||||
});
|
||||
}
|
||||
|
||||
private void checkUrlVersion() {
|
||||
versionManagerHelper = new VersionManagerHelper(this);
|
||||
if (versionManagerHelper.isCheckVersion())
|
||||
versionManagerSub = Observable.fromCallable(() -> Utilities.getJson(UPDATE_LINK))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.timeout(3000, TimeUnit.MILLISECONDS)
|
||||
.subscribe(result -> isShowDialog(versionManagerHelper.isShow(result)),
|
||||
throwable -> runOnUiThread(() -> isShowDialog(false)));
|
||||
else isShowDialog(false);
|
||||
}
|
||||
|
||||
private void runGame() {
|
||||
pf.saveSettings(TAG_BUILD_NUMBER, versionName);
|
||||
connectionSub = checkConnection();
|
||||
}
|
||||
|
||||
private void startNative() {
|
||||
getDefaultResolution();
|
||||
Intent intent = new Intent(this, GameActivity.class);
|
||||
intent.putExtra("height", height);
|
||||
intent.putExtra("width", width);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == REQUEST_CONNECTION) {
|
||||
checkUrlVersion();
|
||||
} else if (requestCode == REQUEST_UPDATE) {
|
||||
if (resultCode == RESULT_OK)
|
||||
appUpdateManager.registerListener(listener);
|
||||
else
|
||||
startNative();
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanUpOldFiles(boolean isAll) {
|
||||
updateViews(R.string.preparing, View.VISIBLE, View.VISIBLE, View.GONE);
|
||||
Completable delObs;
|
||||
File externalStorage = getExternalFilesDir(null);
|
||||
if (isAll)
|
||||
delObs = Completable.fromAction(() -> deleteFiles(Collections.singletonList(externalStorage)));
|
||||
else {
|
||||
List<File> filesList = Arrays.asList(new File(externalStorage, "cache"),
|
||||
new File(getFilesDir(), "builtin"),
|
||||
new File(getFilesDir(), "games"),
|
||||
new File(externalStorage, "debug.txt"));
|
||||
delObs = Completable.fromAction(() -> deleteFiles(filesList));
|
||||
}
|
||||
cleanSub = delObs.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(() -> startCopy(isAll));
|
||||
}
|
||||
|
||||
private void checkAppVersion() {
|
||||
String prefVersion;
|
||||
try {
|
||||
prefVersion = pf.getBuildNumber();
|
||||
} catch (ClassCastException e) {
|
||||
prefVersion = "1";
|
||||
}
|
||||
if (prefVersion.equals(versionName)) {
|
||||
mProgressBarIndeterminate.setVisibility(View.VISIBLE);
|
||||
runGame();
|
||||
} else {
|
||||
cleanUpOldFiles(prefVersion.equals("0"));
|
||||
}
|
||||
}
|
||||
|
||||
public void updateViews(int text, int textVisib, int progressIndetermVisib, int progressVisib) {
|
||||
mLoading.setText(text);
|
||||
mLoading.setVisibility(textVisib);
|
||||
mProgressBarIndeterminate.setVisibility(progressIndetermVisib);
|
||||
mProgressBar.setVisibility(progressVisib);
|
||||
}
|
||||
|
||||
public void isShowDialog(boolean flag) {
|
||||
if (flag) {
|
||||
if (isLollipop())
|
||||
startUpdate();
|
||||
else
|
||||
showUpdateDialog();
|
||||
} else
|
||||
startNative();
|
||||
}
|
||||
|
||||
private Disposable checkConnection() {
|
||||
return Observable.fromCallable(Utilities::isReachable)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.timeout(4000, TimeUnit.MILLISECONDS)
|
||||
.subscribe(result -> {
|
||||
if (result) checkUrlVersion();
|
||||
else showConnectionDialog();
|
||||
},
|
||||
throwable -> runOnUiThread(this::showConnectionDialog));
|
||||
}
|
||||
|
||||
private void startCopy(boolean isAll) {
|
||||
zips = getZipsFromAssets(this);
|
||||
if (!isAll) zips.remove(WORLDS);
|
||||
copySub = Completable.fromAction(() -> runOnUiThread(() -> copyAssets(zips)))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(() -> startUnzipService(zips));
|
||||
}
|
||||
|
||||
private void copyAssets(ArrayList<String> zips) {
|
||||
for (String zipName : zips) {
|
||||
try (InputStream in = getAssets().open("data/" + zipName)) {
|
||||
FileUtils.copyInputStreamToFile(in, new File(getCacheDir(), zipName));
|
||||
} catch (IOException e) {
|
||||
Bugsnag.leaveBreadcrumb("Failed to copy " + zipName);
|
||||
if (e.getLocalizedMessage().contains(NO_SPACE_LEFT))
|
||||
showRestartDialog(NO_SPACE_LEFT);
|
||||
else {
|
||||
showRestartDialog("");
|
||||
Bugsnag.notify(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startUnzipService(ArrayList<String> file) {
|
||||
Intent intent = new Intent(this, UnzipService.class);
|
||||
intent.putStringArrayListExtra(UnzipService.EXTRA_KEY_IN_FILE, file);
|
||||
startService(intent);
|
||||
}
|
||||
|
||||
private void showRestartDialog(final String source) {
|
||||
String message;
|
||||
if (NO_SPACE_LEFT.equals(source))
|
||||
message = getString(R.string.no_space);
|
||||
else
|
||||
message = getString(R.string.restart);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setMessage(message)
|
||||
.setPositiveButton(R.string.ok, (dialogInterface, i) -> restartApp());
|
||||
builder.setCancelable(false);
|
||||
final AlertDialog dialog = builder.create();
|
||||
if (!isFinishing())
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void restartApp() {
|
||||
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
|
||||
int mPendingIntentId = 1337;
|
||||
AlarmManager mgr = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
|
||||
if (mgr != null)
|
||||
mgr.set(AlarmManager.RTC, System.currentTimeMillis(), PendingIntent.getActivity(
|
||||
getApplicationContext(), mPendingIntentId, intent, PendingIntent.FLAG_CANCEL_CURRENT));
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(boolean isContinue) {
|
||||
if (isFinishing()) return;
|
||||
if (isContinue) init();
|
||||
else finish();
|
||||
}
|
||||
|
||||
private void showConnectionDialog() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setMessage(R.string.conn_message)
|
||||
.setPositiveButton(R.string.conn_wifi, (dialogInterface, i) -> startHandledActivity(new Intent(ACTION_WIFI_SETTINGS)))
|
||||
.setNegativeButton(R.string.conn_mobile, (dialogInterface, i) -> startHandledActivity(new Intent(ACTION_WIRELESS_SETTINGS)))
|
||||
.setNeutralButton(R.string.ignore, (dialogInterface, i) -> startNative());
|
||||
builder.setCancelable(false);
|
||||
final AlertDialog dialog = builder.create();
|
||||
if (!isFinishing())
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void startHandledActivity(Intent intent) {
|
||||
try {
|
||||
startActivityForResult(intent, REQUEST_CONNECTION);
|
||||
} catch (Exception e) {
|
||||
startNative();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
MultiCraft
|
||||
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 3.0 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 com.multicraft.game;
|
||||
|
||||
import androidx.multidex.MultiDexApplication;
|
||||
|
||||
import com.bugsnag.android.Bugsnag;
|
||||
|
||||
public class MyApplication extends MultiDexApplication {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
Bugsnag.start(this);
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
/*
|
||||
Minetest
|
||||
MultiCraft
|
||||
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
|
||||
the Free Software Foundation; either version 3.0 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
@ -18,7 +18,7 @@ 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;
|
||||
package com.multicraft.game;
|
||||
|
||||
import android.app.IntentService;
|
||||
import android.app.Notification;
|
||||
@ -26,39 +26,44 @@ import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.bugsnag.android.Bugsnag;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import static com.multicraft.game.helpers.ApiLevelHelper.isOreo;
|
||||
import static com.multicraft.game.helpers.Constants.NO_SPACE_LEFT;
|
||||
import static com.multicraft.game.helpers.Utilities.getLocationByZip;
|
||||
import static com.multicraft.game.helpers.Utilities.getZipsFromAssets;
|
||||
|
||||
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_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 String ACTION_UPDATE = "com.multicraft.game.UPDATE";
|
||||
public static final String EXTRA_KEY_IN_FILE = "com.multicraft.game.file";
|
||||
public static final String ACTION_PROGRESS = "com.multicraft.game.progress";
|
||||
public static final String ACTION_FAILURE = "com.multicraft.game.failure";
|
||||
public static final int UNZIP_SUCCESS = -1;
|
||||
public static final int UNZIP_FAILURE = -2;
|
||||
private final int id = 1;
|
||||
private NotificationManager mNotifyManager;
|
||||
private boolean isSuccess = true;
|
||||
private String failureMessage;
|
||||
private boolean isSuccess = true;
|
||||
|
||||
public UnzipService() {
|
||||
super("net.minetest.minetest.UnzipService");
|
||||
super("com.multicraft.game.UnzipService");
|
||||
}
|
||||
|
||||
private void isDir(String dir, String location) {
|
||||
File f = new File(location, dir);
|
||||
if (!f.isDirectory())
|
||||
f.mkdirs();
|
||||
private void isDir(String dir, String unzipLocation) {
|
||||
File f = new File(unzipLocation, dir);
|
||||
if (!f.mkdirs() && !f.isDirectory())
|
||||
Bugsnag.leaveBreadcrumb(f + " (destination) folder was not created");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -68,13 +73,14 @@ public class UnzipService extends IntentService {
|
||||
}
|
||||
|
||||
private void createNotification() {
|
||||
String name = "net.minetest.minetest";
|
||||
String channelId = "Minetest channel";
|
||||
String description = "notifications from Minetest";
|
||||
// There are hardcoding only for show it's just strings
|
||||
String name = "com.multicraft.game";
|
||||
String channelId = "MultiCraft channel"; // The user-visible name of the channel.
|
||||
String description = "notifications from MultiCraft"; // The user-visible description of the channel.
|
||||
Notification.Builder builder;
|
||||
if (mNotifyManager == null)
|
||||
mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
if (isOreo()) {
|
||||
int importance = NotificationManager.IMPORTANCE_LOW;
|
||||
NotificationChannel mChannel = null;
|
||||
if (mNotifyManager != null)
|
||||
@ -89,44 +95,52 @@ public class UnzipService extends IntentService {
|
||||
mNotifyManager.createNotificationChannel(mChannel);
|
||||
}
|
||||
builder = new Notification.Builder(this, channelId);
|
||||
} else {
|
||||
} else
|
||||
builder = new Notification.Builder(this);
|
||||
}
|
||||
builder.setContentTitle(getString(R.string.notification_title))
|
||||
.setSmallIcon(R.mipmap.ic_launcher)
|
||||
.setContentText(getString(R.string.notification_description));
|
||||
.setContentText(getString(R.string.notification_description))
|
||||
.setSmallIcon(R.drawable.update);
|
||||
mNotifyManager.notify(id, builder.build());
|
||||
}
|
||||
|
||||
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;
|
||||
ArrayList<String> zips;
|
||||
if (intent != null)
|
||||
zips = intent.getStringArrayListExtra(EXTRA_KEY_IN_FILE);
|
||||
else
|
||||
zips = getZipsFromAssets(this);
|
||||
String cacheDir = getCacheDir().toString();
|
||||
int per = 0;
|
||||
int size = getSummarySize(zip);
|
||||
File zipFile = new File(zip);
|
||||
int readLen;
|
||||
int size = getSummarySize(zips, cacheDir);
|
||||
byte[] readBuffer = new byte[8192];
|
||||
try (FileInputStream fileInputStream = new FileInputStream(zipFile);
|
||||
ZipInputStream zipInputStream = new ZipInputStream(fileInputStream)) {
|
||||
for (String zip : zips) {
|
||||
String location = getLocationByZip(this, zip);
|
||||
File zipFile = new File(cacheDir, zip);
|
||||
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);
|
||||
int readLen;
|
||||
try (FileInputStream fileInputStream = new FileInputStream(zipFile);
|
||||
ZipInputStream zipInputStream = new ZipInputStream(fileInputStream)) {
|
||||
while ((ze = zipInputStream.getNextEntry()) != null) {
|
||||
String fileName = ze.getName();
|
||||
if (ze.isDirectory()) {
|
||||
++per;
|
||||
isDir(fileName, location);
|
||||
} else {
|
||||
File extractedFile = new File(location, fileName);
|
||||
publishProgress(100 * ++per / size);
|
||||
try (OutputStream outputStream = new FileOutputStream(extractedFile)) {
|
||||
while ((readLen = zipInputStream.read(readBuffer)) != -1) {
|
||||
outputStream.write(readBuffer, 0, readLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
zipFile.delete();
|
||||
} catch (IOException e) {
|
||||
if (!e.getLocalizedMessage().contains(NO_SPACE_LEFT))
|
||||
Bugsnag.notify(e);
|
||||
failureMessage = e.getLocalizedMessage();
|
||||
isSuccess = false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
isSuccess = false;
|
||||
failureMessage = e.getLocalizedMessage();
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,13 +151,15 @@ public class UnzipService extends IntentService {
|
||||
sendBroadcast(intentUpdate);
|
||||
}
|
||||
|
||||
private int getSummarySize(String zip) {
|
||||
private int getSummarySize(ArrayList<String> zips, String path) {
|
||||
int size = 0;
|
||||
try {
|
||||
ZipFile zipSize = new ZipFile(zip);
|
||||
size += zipSize.size();
|
||||
} catch (IOException e) {
|
||||
Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
|
||||
for (String z : zips) {
|
||||
try {
|
||||
ZipFile zipFile = new ZipFile(new File(path, z));
|
||||
size += zipFile.size();
|
||||
} catch (IOException e) {
|
||||
Bugsnag.notify(e);
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
@ -152,6 +168,6 @@ public class UnzipService extends IntentService {
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
mNotifyManager.cancel(id);
|
||||
publishProgress(isSuccess ? SUCCESS : FAILURE);
|
||||
publishProgress(isSuccess ? UNZIP_SUCCESS : UNZIP_FAILURE);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
MultiCraft
|
||||
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 3.0 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 com.multicraft.game.callbacks;
|
||||
|
||||
public interface CallBackListener {
|
||||
void onEvent(boolean isContinue);
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
MultiCraft
|
||||
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 3.0 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 com.multicraft.game.helpers;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
public class AdManager {
|
||||
public static void initAd(final Activity activity, boolean consent) {
|
||||
// NDA code here
|
||||
}
|
||||
|
||||
public static void setAdsCallback(final Activity activity) {
|
||||
// NDA code here
|
||||
}
|
||||
|
||||
public static void startAd(final Activity activity, boolean isFirstTime, boolean isShowNow) {
|
||||
// NDA code here
|
||||
}
|
||||
|
||||
public static void stopAd() {
|
||||
// NDA code here
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
MultiCraft
|
||||
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 3.0 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 com.multicraft.game.helpers;
|
||||
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
|
||||
import static android.os.Build.VERSION_CODES.KITKAT;
|
||||
import static android.os.Build.VERSION_CODES.LOLLIPOP;
|
||||
import static android.os.Build.VERSION_CODES.O;
|
||||
import static android.os.Build.VERSION_CODES.Q;
|
||||
|
||||
public class ApiLevelHelper {
|
||||
public static boolean isGreaterOrEqual(int versionCode) {
|
||||
return SDK_INT >= versionCode;
|
||||
}
|
||||
|
||||
public static boolean isJellyBeanMR1() {
|
||||
return isGreaterOrEqual(JELLY_BEAN_MR1);
|
||||
}
|
||||
|
||||
public static boolean isKitkat() {
|
||||
return isGreaterOrEqual(KITKAT);
|
||||
}
|
||||
|
||||
public static boolean isLollipop() {
|
||||
return isGreaterOrEqual(LOLLIPOP);
|
||||
}
|
||||
|
||||
public static boolean isOreo() {
|
||||
return isGreaterOrEqual(O);
|
||||
}
|
||||
|
||||
public static boolean isAndroidQ() {
|
||||
return isGreaterOrEqual(Q);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
MultiCraft
|
||||
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 3.0 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 com.multicraft.game.helpers;
|
||||
|
||||
import com.multicraft.game.BuildConfig;
|
||||
|
||||
public class Constants {
|
||||
public static final int REQUEST_CONNECTION = 104;
|
||||
public static final int REQUEST_UPDATE = 102;
|
||||
public static final int SESSION_COUNT = 5;
|
||||
public static final String NO_SPACE_LEFT = "ENOSPC";
|
||||
public static final String FILES = "Files.zip";
|
||||
public static final String WORLDS = "worlds.zip";
|
||||
public static final String GAMES = "games.zip";
|
||||
public static final int versionCode = BuildConfig.VERSION_CODE;
|
||||
public static final String versionName = BuildConfig.VERSION_NAME;
|
||||
public static final String appPackage = BuildConfig.APPLICATION_ID;
|
||||
public static final String UPDATE_LINK = "http://updates.multicraft.world/Android.json";
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
/*
|
||||
MultiCraft
|
||||
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 3.0 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 com.multicraft.game.helpers;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.multicraft.game.R;
|
||||
import com.multicraft.game.callbacks.CallBackListener;
|
||||
import com.tedpark.tedpermission.rx2.TedRx2Permission;
|
||||
|
||||
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
|
||||
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
|
||||
|
||||
public class PermissionHelper {
|
||||
private final AppCompatActivity activity;
|
||||
private CallBackListener listener;
|
||||
private PreferencesHelper pf;
|
||||
|
||||
public PermissionHelper(AppCompatActivity activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
public void setListener(CallBackListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public void askPermissions() {
|
||||
pf = PreferencesHelper.getInstance(activity);
|
||||
askStoragePermissions();
|
||||
}
|
||||
|
||||
// permission block
|
||||
@SuppressLint("CheckResult")
|
||||
private void askStoragePermissions() {
|
||||
TedRx2Permission.with(activity)
|
||||
.setPermissions(WRITE_EXTERNAL_STORAGE)
|
||||
.request()
|
||||
.subscribe(tedPermissionResult -> {
|
||||
if (tedPermissionResult.isGranted()) {
|
||||
if (pf.getLaunchTimes() % 3 == 1)
|
||||
askLocationPermissions();
|
||||
else listener.onEvent(true);
|
||||
} else {
|
||||
if (TedRx2Permission.canRequestPermission(activity, WRITE_EXTERNAL_STORAGE))
|
||||
askStorageRationalePermissions();
|
||||
else askStorageWhenDoNotShow();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// storage permissions block
|
||||
@SuppressLint("CheckResult")
|
||||
private void askStorageRationalePermissions() {
|
||||
TedRx2Permission.with(activity)
|
||||
.setRationaleMessage(R.string.explain)
|
||||
.setDeniedMessage(R.string.denied)
|
||||
.setDeniedCloseButtonText(R.string.close_game)
|
||||
.setGotoSettingButtonText(R.string.settings)
|
||||
.setPermissions(WRITE_EXTERNAL_STORAGE)
|
||||
.request()
|
||||
.subscribe(tedPermissionResult -> {
|
||||
if (tedPermissionResult.isGranted()) {
|
||||
if (pf.getLaunchTimes() % 3 == 1)
|
||||
askLocationPermissions();
|
||||
else listener.onEvent(true);
|
||||
} else {
|
||||
listener.onEvent(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private void askStorageWhenDoNotShow() {
|
||||
TedRx2Permission.with(activity)
|
||||
.setDeniedMessage(R.string.denied)
|
||||
.setDeniedCloseButtonText(R.string.close_game)
|
||||
.setGotoSettingButtonText(R.string.settings)
|
||||
.setPermissions(WRITE_EXTERNAL_STORAGE)
|
||||
.request()
|
||||
.subscribe(tedPermissionResult -> {
|
||||
if (tedPermissionResult.isGranted()) {
|
||||
if (pf.getLaunchTimes() % 3 == 1)
|
||||
askLocationPermissions();
|
||||
else listener.onEvent(true);
|
||||
} else {
|
||||
listener.onEvent(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// location permissions block
|
||||
@SuppressLint("CheckResult")
|
||||
private void askLocationPermissions() {
|
||||
TedRx2Permission.with(activity)
|
||||
.setPermissions(ACCESS_FINE_LOCATION)
|
||||
.request()
|
||||
.subscribe(tedPermissionResult -> {
|
||||
if (tedPermissionResult.isGranted()) {
|
||||
listener.onEvent(true);
|
||||
} else {
|
||||
if (TedRx2Permission.canRequestPermission(activity, ACCESS_FINE_LOCATION))
|
||||
askLocationRationalePermissions();
|
||||
else listener.onEvent(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private void askLocationRationalePermissions() {
|
||||
TedRx2Permission.with(activity)
|
||||
.setRationaleMessage(R.string.location)
|
||||
.setPermissions(ACCESS_FINE_LOCATION)
|
||||
.request()
|
||||
.subscribe(tedPermissionResult -> listener.onEvent(true));
|
||||
}
|
||||
}
|
@ -0,0 +1,132 @@
|
||||
/*
|
||||
MultiCraft
|
||||
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 3.0 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 com.multicraft.game.helpers;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
public class PreferencesHelper {
|
||||
public static final String TAG_SHORTCUT_EXIST = "createShortcut";
|
||||
public static final String TAG_BUILD_NUMBER = "buildNumber";
|
||||
public static final String TAG_LAUNCH_TIMES = "launchTimes";
|
||||
public static final String TAG_COPY_OLD_WORLDS = "copyOldWorlds";
|
||||
public static final String TAG_LAST_RATE_VERSION_CODE = "lastRateVersionCode";
|
||||
public static final String TAG_RATE_MIN_VERSION_CODE = "rateMinVersionCode";
|
||||
public static final String TAG_EXIT_GAME_COUNT = "exitGameCount";
|
||||
public static final String TAG_REVIEW_ENABLE = "reviewEnable";
|
||||
public static final String TAG_OPT_OUT = "optOut";
|
||||
public static final String IS_ASK_CONSENT = "isAskConsent";
|
||||
public static final String IS_LOADED = "interstitialLoaded";
|
||||
public static final String RV_LOADED = "rewardedVideoLoaded";
|
||||
public static final String ADS_DELAY = "adsDelay";
|
||||
public static final String ADS_REPEAT = "adsRepeat";
|
||||
public static final String ADS_ENABLE = "adsEnable";
|
||||
private static final String SETTINGS = "MultiCraftSettings";
|
||||
|
||||
private static PreferencesHelper instance;
|
||||
private static SharedPreferences sharedPreferences;
|
||||
|
||||
private PreferencesHelper(Context context) {
|
||||
sharedPreferences = context.getSharedPreferences(SETTINGS, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
public static PreferencesHelper getInstance(Context context) {
|
||||
if (instance == null) {
|
||||
synchronized (PreferencesHelper.class) {
|
||||
if (instance == null)
|
||||
instance = new PreferencesHelper(context.getApplicationContext());
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public boolean isCreateShortcut() {
|
||||
return sharedPreferences.getBoolean(TAG_SHORTCUT_EXIST, false);
|
||||
}
|
||||
|
||||
public boolean isInterstitialLoaded() {
|
||||
return sharedPreferences.getBoolean(IS_LOADED, false);
|
||||
}
|
||||
|
||||
public boolean isVideoLoaded() {
|
||||
return sharedPreferences.getBoolean(RV_LOADED, false);
|
||||
}
|
||||
|
||||
public boolean isAskConsent() {
|
||||
return sharedPreferences.getBoolean(IS_ASK_CONSENT, true);
|
||||
}
|
||||
|
||||
public boolean isWorldsCopied() {
|
||||
return sharedPreferences.getBoolean(TAG_COPY_OLD_WORLDS, false);
|
||||
}
|
||||
|
||||
public String getBuildNumber() {
|
||||
return sharedPreferences.getString(TAG_BUILD_NUMBER, "0");
|
||||
}
|
||||
|
||||
public int getLaunchTimes() {
|
||||
return sharedPreferences.getInt(TAG_LAUNCH_TIMES, 0);
|
||||
}
|
||||
|
||||
public int getLastRateVersionCode() {
|
||||
return sharedPreferences.getInt(TAG_LAST_RATE_VERSION_CODE, 0);
|
||||
}
|
||||
|
||||
public int getRateMinVersionCode() {
|
||||
return sharedPreferences.getInt(TAG_RATE_MIN_VERSION_CODE, 0);
|
||||
}
|
||||
|
||||
public int getExitGameCount() {
|
||||
return sharedPreferences.getInt(TAG_EXIT_GAME_COUNT, 0);
|
||||
}
|
||||
|
||||
public int getAdsDelay() {
|
||||
return sharedPreferences.getInt(ADS_DELAY, 600);
|
||||
}
|
||||
|
||||
public int getAdsRepeat() {
|
||||
return sharedPreferences.getInt(ADS_REPEAT, 900);
|
||||
}
|
||||
|
||||
public boolean isAdsEnable() {
|
||||
return sharedPreferences.getBoolean(ADS_ENABLE, true);
|
||||
}
|
||||
|
||||
public boolean isReviewEnable() {
|
||||
return sharedPreferences.getBoolean(TAG_REVIEW_ENABLE, true);
|
||||
}
|
||||
|
||||
public boolean isOptOut() {
|
||||
return sharedPreferences.getBoolean(TAG_OPT_OUT, false);
|
||||
}
|
||||
|
||||
public void saveSettings(String tag, boolean bool) {
|
||||
sharedPreferences.edit().putBoolean(tag, bool).apply();
|
||||
}
|
||||
|
||||
public void saveSettings(String tag, String value) {
|
||||
sharedPreferences.edit().putString(tag, value).apply();
|
||||
}
|
||||
|
||||
public void saveSettings(String tag, int value) {
|
||||
sharedPreferences.edit().putInt(tag, value).apply();
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
MultiCraft
|
||||
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 3.0 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 com.multicraft.game.helpers;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.NativeActivity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.view.View;
|
||||
import android.widget.RatingBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.multicraft.game.R;
|
||||
|
||||
import static com.multicraft.game.helpers.ApiLevelHelper.isKitkat;
|
||||
import static com.multicraft.game.helpers.Constants.SESSION_COUNT;
|
||||
import static com.multicraft.game.helpers.PreferencesHelper.TAG_OPT_OUT;
|
||||
import static com.multicraft.game.helpers.Utilities.getStoreUrl;
|
||||
|
||||
public class RateMeHelper {
|
||||
private static PreferencesHelper pf;
|
||||
|
||||
public static void onStart(NativeActivity activity) {
|
||||
pf = PreferencesHelper.getInstance(activity);
|
||||
}
|
||||
|
||||
private static boolean isEnoughTimePassed() {
|
||||
return (pf.getLastRateVersionCode() == 0) && pf.getLaunchTimes() >= SESSION_COUNT
|
||||
&& pf.getExitGameCount() >= SESSION_COUNT;
|
||||
}
|
||||
|
||||
private static boolean isWorthToReview() {
|
||||
return (pf.getLastRateVersionCode() != 0)
|
||||
&& pf.getRateMinVersionCode() > pf.getLastRateVersionCode();
|
||||
}
|
||||
|
||||
public static boolean shouldAskForReview() {
|
||||
return pf.isReviewEnable() && (isEnoughTimePassed() || isWorthToReview());
|
||||
}
|
||||
|
||||
public static boolean shouldShowRateDialog() {
|
||||
if (pf.isOptOut())
|
||||
return false;
|
||||
else {
|
||||
return shouldAskForReview();
|
||||
}
|
||||
}
|
||||
|
||||
public static void showRateDialog(NativeActivity activity) {
|
||||
final Dialog dialog = new Dialog(activity, R.style.RateMe);
|
||||
dialog.setCancelable(false);
|
||||
if (isKitkat())
|
||||
dialog.getWindow().getDecorView().setSystemUiVisibility(
|
||||
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
|
||||
dialog.setContentView(R.layout.rate_dialog);
|
||||
RatingBar ratingBar = dialog.findViewById(R.id.ratingBar);
|
||||
ratingBar.setOnRatingBarChangeListener((ratingBar1, rating, fromUser) -> {
|
||||
if (rating >= 4) {
|
||||
try {
|
||||
Toast.makeText(activity, R.string.thank, Toast.LENGTH_LONG).show();
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(getStoreUrl()));
|
||||
activity.startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
// nothing
|
||||
}
|
||||
dialog.dismiss();
|
||||
pf.saveSettings(TAG_OPT_OUT, true);
|
||||
} else {
|
||||
dialog.dismiss();
|
||||
Toast.makeText(activity, R.string.sad, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
if (!activity.isFinishing())
|
||||
dialog.show();
|
||||
}
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
/*
|
||||
MultiCraft
|
||||
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 3.0 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 com.multicraft.game.helpers;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
|
||||
import com.bugsnag.android.Bugsnag;
|
||||
import com.multicraft.game.MainActivity;
|
||||
import com.multicraft.game.R;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
import static android.os.Environment.getExternalStorageDirectory;
|
||||
import static com.multicraft.game.helpers.ApiLevelHelper.isKitkat;
|
||||
import static com.multicraft.game.helpers.Constants.FILES;
|
||||
import static com.multicraft.game.helpers.Constants.GAMES;
|
||||
import static com.multicraft.game.helpers.Constants.WORLDS;
|
||||
import static com.multicraft.game.helpers.Constants.appPackage;
|
||||
import static com.multicraft.game.helpers.PreferencesHelper.TAG_SHORTCUT_EXIST;
|
||||
|
||||
public class Utilities {
|
||||
private static boolean isInternetAvailable(String url) {
|
||||
try {
|
||||
HttpURLConnection urlc =
|
||||
(HttpURLConnection) new URL(url).openConnection();
|
||||
urlc.setRequestProperty("Connection", "close");
|
||||
urlc.setConnectTimeout(2000);
|
||||
urlc.connect();
|
||||
int ResponseCode = urlc.getResponseCode();
|
||||
return ResponseCode == HttpURLConnection.HTTP_NO_CONTENT ||
|
||||
ResponseCode == HttpURLConnection.HTTP_OK;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isReachable() {
|
||||
return isInternetAvailable("http://clients3.google.com/generate_204") ||
|
||||
isInternetAvailable("http://servers.multicraft.world");
|
||||
}
|
||||
|
||||
public static void deleteFiles(List<String> files, String path) {
|
||||
for (String f : files) {
|
||||
File file = new File(path, f);
|
||||
if (file.exists())
|
||||
FileUtils.deleteQuietly(file);
|
||||
}
|
||||
}
|
||||
|
||||
public static void deleteFiles(List<File> files) {
|
||||
for (File file : files) {
|
||||
if (file != null && file.exists())
|
||||
FileUtils.deleteQuietly(file);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getStoreUrl() {
|
||||
return "market://details?id=" + appPackage;
|
||||
}
|
||||
|
||||
public static void makeFullScreen(Activity activity) {
|
||||
if (isKitkat())
|
||||
activity.getWindow().getDecorView().setSystemUiVisibility(
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
|
||||
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
|
||||
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
|
||||
}
|
||||
|
||||
public static Drawable getIcon(Activity activity) {
|
||||
try {
|
||||
return activity.getPackageManager().getApplicationIcon(activity.getPackageName());
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Bugsnag.notify(e);
|
||||
return activity.getResources().getDrawable(R.mipmap.ic_launcher);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addShortcut(Activity activity) {
|
||||
ActivityManager activityManager =
|
||||
(ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
int size = 0;
|
||||
if (activityManager != null)
|
||||
size = activityManager.getLauncherLargeIconSize();
|
||||
Bitmap shortcutIconBitmap = ((BitmapDrawable) getIcon(activity)).getBitmap();
|
||||
if (shortcutIconBitmap.getWidth() != size || shortcutIconBitmap.getHeight() != size)
|
||||
shortcutIconBitmap = Bitmap.createScaledBitmap(shortcutIconBitmap, size, size, true);
|
||||
PreferencesHelper.getInstance(activity).saveSettings(TAG_SHORTCUT_EXIST, true);
|
||||
Intent shortcutIntent = new Intent(activity, MainActivity.class);
|
||||
shortcutIntent.setAction(Intent.ACTION_MAIN);
|
||||
Intent addIntent = new Intent();
|
||||
addIntent.putExtra("duplicate", false);
|
||||
addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
|
||||
addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, activity.getResources().getString(R.string.app_name));
|
||||
addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, shortcutIconBitmap);
|
||||
addIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
|
||||
activity.getApplicationContext().sendBroadcast(addIntent);
|
||||
}
|
||||
|
||||
public static String getJson(String url) {
|
||||
OkHttpClient client = new OkHttpClient.Builder()
|
||||
.callTimeout(3000, TimeUnit.MILLISECONDS)
|
||||
.build();
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.build();
|
||||
try {
|
||||
Response response = client.newCall(request).execute();
|
||||
return response.body().string();
|
||||
} catch (IOException | NullPointerException e) {
|
||||
return "{}";
|
||||
}
|
||||
}
|
||||
|
||||
public static String getLocationByZip(Context context, String zipName) {
|
||||
String path;
|
||||
switch (zipName) {
|
||||
case FILES:
|
||||
case GAMES:
|
||||
path = context.getFilesDir().toString();
|
||||
break;
|
||||
case WORLDS:
|
||||
try {
|
||||
path = context.getExternalFilesDir(null).toString();
|
||||
} catch (NullPointerException e) {
|
||||
path = getExternalStorageDirectory() + "/Android/data/com.multicraft.game/files";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("No such zip name");
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
public static ArrayList<String> getZipsFromAssets(Context context) {
|
||||
try {
|
||||
return new ArrayList<>(Arrays.asList(context.getAssets().list("data")));
|
||||
} catch (IOException e) {
|
||||
return new ArrayList<>(Arrays.asList(FILES, GAMES, WORLDS));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
/*
|
||||
MultiCraft
|
||||
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 3.0 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 com.multicraft.game.helpers;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.text.Editable;
|
||||
import android.text.Html;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.multicraft.game.JsonSettings;
|
||||
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static com.multicraft.game.helpers.Constants.versionCode;
|
||||
import static com.multicraft.game.helpers.PreferencesHelper.ADS_DELAY;
|
||||
import static com.multicraft.game.helpers.PreferencesHelper.ADS_ENABLE;
|
||||
import static com.multicraft.game.helpers.PreferencesHelper.ADS_REPEAT;
|
||||
import static com.multicraft.game.helpers.PreferencesHelper.TAG_RATE_MIN_VERSION_CODE;
|
||||
import static com.multicraft.game.helpers.PreferencesHelper.TAG_REVIEW_ENABLE;
|
||||
import static com.multicraft.game.helpers.Utilities.getStoreUrl;
|
||||
|
||||
public class VersionManagerHelper {
|
||||
private final CustomTagHandler customTagHandler;
|
||||
private final String PREF_REMINDER_TIME = "w.reminder.time";
|
||||
private final AppCompatActivity activity;
|
||||
private String message, updateUrl;
|
||||
|
||||
public VersionManagerHelper(AppCompatActivity act) {
|
||||
this.activity = act;
|
||||
this.customTagHandler = new CustomTagHandler();
|
||||
}
|
||||
|
||||
public boolean isCheckVersion() {
|
||||
long currentTimeStamp = Calendar.getInstance().getTimeInMillis();
|
||||
long reminderTimeStamp = getReminderTime();
|
||||
return currentTimeStamp > reminderTimeStamp;
|
||||
}
|
||||
|
||||
private boolean isBadVersion(List<Integer> badVersions) {
|
||||
return badVersions.contains(versionCode);
|
||||
}
|
||||
|
||||
private JsonSettings parseJson(String result) {
|
||||
JsonSettings settings = new Gson().fromJson(result, JsonSettings.class);
|
||||
String lang = Locale.getDefault().getLanguage();
|
||||
String content = lang.equals("ru") ? settings.getContentRus() : settings.getContentEng();
|
||||
setMessage(content);
|
||||
setUpdateUrl("market://details?id=" + settings.getPackageName());
|
||||
savePrefSettings(settings);
|
||||
return settings;
|
||||
}
|
||||
|
||||
private void savePrefSettings(JsonSettings settings) {
|
||||
PreferencesHelper pf = PreferencesHelper.getInstance(activity);
|
||||
pf.saveSettings(TAG_RATE_MIN_VERSION_CODE, settings.getRateMinVersionCode());
|
||||
pf.saveSettings(TAG_REVIEW_ENABLE, settings.isReviewEnabled());
|
||||
pf.saveSettings(ADS_DELAY, settings.getAdsDelay());
|
||||
pf.saveSettings(ADS_REPEAT, settings.getAdsRepeat());
|
||||
pf.saveSettings(ADS_ENABLE, settings.isAdsEnabled());
|
||||
}
|
||||
|
||||
public boolean isShow(String result) {
|
||||
if (result.equals("{}")) return false;
|
||||
JsonSettings jsonSettings = parseJson(result);
|
||||
return (versionCode < jsonSettings.getVersionCode()) ||
|
||||
isBadVersion(jsonSettings.getBadVersionCodes());
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
String defaultMessage = "What's new?";
|
||||
return message != null ? message : defaultMessage;
|
||||
}
|
||||
|
||||
private void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getUpdateUrl() {
|
||||
return updateUrl != null ? updateUrl : getStoreUrl();
|
||||
}
|
||||
|
||||
private void setUpdateUrl(String updateUrl) {
|
||||
this.updateUrl = updateUrl;
|
||||
}
|
||||
|
||||
public void updateNow(String url) {
|
||||
if (url != null) {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
activity.startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void remindMeLater() {
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.add(Calendar.MINUTE, 1);
|
||||
long reminderTimeStamp = c.getTimeInMillis();
|
||||
setReminderTime(reminderTimeStamp);
|
||||
}
|
||||
|
||||
private long getReminderTime() {
|
||||
return PreferenceManager.getDefaultSharedPreferences(activity).getLong(
|
||||
PREF_REMINDER_TIME, 0);
|
||||
}
|
||||
|
||||
private void setReminderTime(long reminderTimeStamp) {
|
||||
PreferenceManager.getDefaultSharedPreferences(activity).edit().putLong(
|
||||
PREF_REMINDER_TIME, reminderTimeStamp).apply();
|
||||
}
|
||||
|
||||
public CustomTagHandler getCustomTagHandler() {
|
||||
return customTagHandler;
|
||||
}
|
||||
|
||||
private static class CustomTagHandler implements Html.TagHandler {
|
||||
@Override
|
||||
public void handleTag(boolean opening, String tag, Editable output,
|
||||
XMLReader xmlReader) {
|
||||
// you may add more tag handler which are not supported by android here
|
||||
if ("li".equals(tag)) {
|
||||
if (opening)
|
||||
output.append(" \u2022 ");
|
||||
else
|
||||
output.append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,126 +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.app.NativeActivity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
||||
public class GameActivity extends NativeActivity {
|
||||
static {
|
||||
System.loadLibrary("c++_shared");
|
||||
System.loadLibrary("Minetest");
|
||||
}
|
||||
|
||||
private int messageReturnCode;
|
||||
private String 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);
|
||||
messageReturnCode = -1;
|
||||
messageReturnValue = "";
|
||||
}
|
||||
|
||||
private void makeFullScreen() {
|
||||
if (Build.VERSION.SDK_INT >= 19)
|
||||
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();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
makeFullScreen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// Ignore the back press so Minetest can handle it
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == 101) {
|
||||
if (resultCode == RESULT_OK) {
|
||||
String text = data.getStringExtra("text");
|
||||
messageReturnCode = 0;
|
||||
messageReturnValue = text;
|
||||
} else
|
||||
messageReturnCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
public void showDialog(String acceptButton, String hint, String current, int editType) {
|
||||
Intent intent = new Intent(this, InputDialogActivity.class);
|
||||
Bundle params = new Bundle();
|
||||
params.putString("acceptButton", acceptButton);
|
||||
params.putString("hint", hint);
|
||||
params.putString("current", current);
|
||||
params.putInt("editType", editType);
|
||||
intent.putExtras(params);
|
||||
startActivityForResult(intent, 101);
|
||||
messageReturnValue = "";
|
||||
messageReturnCode = -1;
|
||||
}
|
||||
|
||||
public int getDialogState() {
|
||||
return messageReturnCode;
|
||||
}
|
||||
|
||||
public String getDialogValue() {
|
||||
messageReturnCode = -1;
|
||||
return messageReturnValue;
|
||||
}
|
||||
|
||||
public float getDensity() {
|
||||
return getResources().getDisplayMetrics().density;
|
||||
}
|
||||
|
||||
public int getDisplayHeight() {
|
||||
return getResources().getDisplayMetrics().heightPixels;
|
||||
}
|
||||
|
||||
public int getDisplayWidth() {
|
||||
return getResources().getDisplayMetrics().widthPixels;
|
||||
}
|
||||
|
||||
public void openURL(String url) {
|
||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
startActivity(browserIntent);
|
||||
}
|
||||
}
|
@ -1,98 +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.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class InputDialogActivity extends AppCompatActivity {
|
||||
private AlertDialog alertDialog;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Bundle b = getIntent().getExtras();
|
||||
int editType = Objects.requireNonNull(b).getInt("editType");
|
||||
String hint = b.getString("hint");
|
||||
String current = b.getString("current");
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
EditText editText = new EditText(this);
|
||||
builder.setView(editText);
|
||||
editText.requestFocus();
|
||||
editText.setHint(hint);
|
||||
editText.setText(current);
|
||||
final InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
|
||||
Objects.requireNonNull(imm).toggleSoftInput(InputMethodManager.SHOW_FORCED,
|
||||
InputMethodManager.HIDE_IMPLICIT_ONLY);
|
||||
if (editType == 3)
|
||||
editText.setInputType(InputType.TYPE_CLASS_TEXT |
|
||||
InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
||||
else
|
||||
editText.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||
editText.setOnKeyListener((view, KeyCode, event) -> {
|
||||
if (KeyCode == KeyEvent.KEYCODE_ENTER) {
|
||||
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
|
||||
pushResult(editText.getText().toString());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
alertDialog = builder.create();
|
||||
if (!this.isFinishing())
|
||||
alertDialog.show();
|
||||
alertDialog.setOnCancelListener(dialog -> {
|
||||
pushResult(editText.getText().toString());
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
alertDialog.dismiss();
|
||||
makeFullScreen();
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
private void pushResult(String text) {
|
||||
Intent resultData = new Intent();
|
||||
resultData.putExtra("text", text);
|
||||
setResult(AppCompatActivity.RESULT_OK, resultData);
|
||||
alertDialog.dismiss();
|
||||
makeFullScreen();
|
||||
finish();
|
||||
}
|
||||
|
||||
private void makeFullScreen() {
|
||||
if (Build.VERSION.SDK_INT >= 19)
|
||||
this.getWindow().getDecorView().setSystemUiVisibility(
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
|
||||
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
|
||||
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
|
||||
}
|
||||
}
|
@ -1,153 +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.Manifest;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
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;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
private final static int versionCode = BuildConfig.VERSION_CODE;
|
||||
private final static int PERMISSIONS = 1;
|
||||
private static final String[] REQUIRED_SDK_PERMISSIONS =
|
||||
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)
|
||||
progress = intent.getIntExtra(ACTION_PROGRESS, 0);
|
||||
if (progress >= 0) {
|
||||
if (mProgressBar != null) {
|
||||
mProgressBar.setVisibility(View.VISIBLE);
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
IntentFilter filter = new IntentFilter(ACTION_UPDATE);
|
||||
registerReceiver(myReceiver, filter);
|
||||
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)
|
||||
checkPermission();
|
||||
else
|
||||
checkAppVersion();
|
||||
}
|
||||
|
||||
private void checkPermission() {
|
||||
final List<String> missingPermissions = new ArrayList<>();
|
||||
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()) {
|
||||
final String[] permissions = missingPermissions
|
||||
.toArray(new String[0]);
|
||||
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) {
|
||||
if (requestCode == PERMISSIONS) {
|
||||
for (int grantResult : grantResults) {
|
||||
if (grantResult != PackageManager.PERMISSION_GRANTED) {
|
||||
Toast.makeText(this, R.string.not_granted, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
}
|
||||
checkAppVersion();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAppVersion() {
|
||||
if (sharedPreferences.getInt(TAG_VERSION_CODE, 0) == versionCode)
|
||||
startNative();
|
||||
else
|
||||
new CopyZipTask(this).execute(getCacheDir() + "/Minetest.zip");
|
||||
}
|
||||
|
||||
private void startNative() {
|
||||
sharedPreferences.edit().putInt(TAG_VERSION_CODE, versionCode).apply();
|
||||
Intent intent = new Intent(this, GameActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// Prevent abrupt interruption when copy game files from assets
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
unregisterReceiver(myReceiver);
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 83 B After Width: | Height: | Size: 8.3 KiB |
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@android:color/white" />
|
||||
<corners android:radius="12dp" />
|
||||
</shape>
|
@ -0,0 +1,10 @@
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#FFFFFF" />
|
||||
<corners android:radius="8dp" />
|
||||
<padding android:left="8dp" />
|
||||
<stroke android:width="2dp" android:color="#59000000" />
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/background">
|
||||
<shape>
|
||||
<stroke
|
||||
android:width="2.5dp"
|
||||
android:color="#000000" />
|
||||
<padding
|
||||
android:bottom="3dp"
|
||||
android:left="3dp"
|
||||
android:right="3dp"
|
||||
android:top="3dp" />
|
||||
<corners android:radius="40dip" />
|
||||
<gradient
|
||||
android:endColor="#6a6a6a"
|
||||
android:startColor="#6a6a6a" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<item android:id="@+id/progress">
|
||||
<clip>
|
||||
<shape>
|
||||
<corners android:radius="40dip" />
|
||||
</shape>
|
||||
</clip>
|
||||
</item>
|
||||
</layer-list>
|
@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#008577"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
BIN
build/android/app/src/main/res/drawable/update.png
Normal file
After Width: | Height: | Size: 134 B |
@ -1,30 +1,39 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/activity_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/bg">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:id="@+id/PB1"
|
||||
style="@style/CustomProgressBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="30dp"
|
||||
android:layout_width="400dp"
|
||||
android:layout_height="45dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginLeft="90dp"
|
||||
android:layout_marginRight="90dp"
|
||||
android:layout_marginLeft="120dp"
|
||||
android:layout_marginRight="120dp"
|
||||
android:indeterminate="false"
|
||||
android:max="100"
|
||||
android:visibility="gone" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/PB2"
|
||||
style="Widget.AppCompat.ProgressBar"
|
||||
android:layout_width="75dp"
|
||||
android:layout_height="75dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView"
|
||||
android:id="@+id/tv_progress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/progressBar"
|
||||
android:layout_below="@id/PB2"
|
||||
android:layout_centerInParent="true"
|
||||
android:background="@android:color/transparent"
|
||||
android:text="@string/loading"
|
||||
android:textColor="#FEFEFE"
|
||||
android:textColor="#fefefe"
|
||||
android:textSize="17sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
50
build/android/app/src/main/res/layout/rate_dialog.xml
Normal file
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ratingTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/rate_dialog_title"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<RatingBar
|
||||
android:id="@+id/ratingBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="10dp"
|
||||
android:numStars="5"
|
||||
android:stepSize="1" />
|
||||
|
||||
<EditText
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:background="@drawable/custom_edittext_rounded"
|
||||
android:clickable="false"
|
||||
android:cursorVisible="false"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false"
|
||||
android:hint="@string/rate_description"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="text"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="5dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:enabled="false"
|
||||
android:text="@string/rate_submit"
|
||||
android:textColor="#008c80"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
After Width: | Height: | Size: 18 KiB |
BIN
build/android/app/src/main/res/mipmap-v25/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 32 KiB |
44
build/android/app/src/main/res/values-ru/strings.xml
Normal file
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<!-- подготовка к запуску -->
|
||||
<string name="preparing">Подготовка к запуску…</string>
|
||||
<string name="loading">Загрузка…</string>
|
||||
<string name="loadingp">Загрузка… %d%%</string>
|
||||
<string name="downloading">Загрузка новой версии…</string>
|
||||
<string name="downloadingp">Загрузка новой версии… %d%%</string>
|
||||
<string name="notification_title">Загрузка MultiCraft</string>
|
||||
<string name="notification_description">Осталось меньше минуты…</string>
|
||||
<string name="restart">Произошла ошибка, игра будет перезапущена автоматически</string>
|
||||
<string name="no_space">Недостаточно места для записи файлов игры, пожалуйста освободите место в памяти</string>
|
||||
|
||||
<!-- разрешения -->
|
||||
<string name="explain">Разрешение на запись необходимо для распаковки текстур и игровых файлов.</string>
|
||||
<string name="location">Доступ к местоположению обеспечивает Вам лучшее взаимодействие с игрой</string>
|
||||
<string name="close_game">Закрыть игру</string>
|
||||
<string name="settings">Настройки</string>
|
||||
<string name="denied">Вы не можете играть в MultiCraft без разрешения на запись.\nПожалуйста, включите его в [Настройки] -> [Разрешения]></string>
|
||||
|
||||
<!-- диалог оценки -->
|
||||
<string name="rate_dialog_title">Оцените MultiCraft!</string>
|
||||
<string name="rate_description">Поделитесь впечатлениями</string>
|
||||
<string name="rate_submit">ОЦЕНИТЬ</string>
|
||||
<string name="sad">Нам жаль, что Вам не понравилась игра!</string>
|
||||
<string name="thank">Пожалуйста, оставьте отзыв для нас. Спасибо!</string>
|
||||
|
||||
<string name="recommend">Загрузка\nрекомендации\nдля Вас:\n%d сек.</string>
|
||||
|
||||
<!-- диалог обновления -->
|
||||
<string name="available">Доступна Новая Версия!</string>
|
||||
<string name="ignore">Игнорировать</string>
|
||||
<string name="later">Позже</string>
|
||||
<string name="update">Обновить</string>
|
||||
|
||||
<!-- диалог отсутствия подключения -->
|
||||
<string name="conn_message">Для полноценной игры, MultiCraft требует подключение к интернету.\nВ противном случае невозможно обновление игры, а так же не доступен мультиплеер!</string>
|
||||
<string name="conn_mobile">3G/4G</string>
|
||||
|
||||
<!-- диалог удаления старой версии -->
|
||||
<string name="del_message">Удалить старую версию MultiCraft?</string>
|
||||
|
||||
</resources>
|
@ -1,10 +1,53 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="label">Minetest</string>
|
||||
<string name="app_name" translatable="false">MultiCraft</string>
|
||||
|
||||
<!-- preparation for start -->
|
||||
<string name="preparing">Preparing to launch…</string>
|
||||
<string name="loading">Loading…</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="loadingp">Loading… %d%%</string>
|
||||
<string name="downloading">Downloading new version…</string>
|
||||
<string name="downloadingp">Downloading new version… %d%%</string>
|
||||
<string name="notification_title">Loading MultiCraft</string>
|
||||
<string name="notification_description">Less than 1 minute…</string>
|
||||
<string name="restart">Unexpected issue, the game will be restarted automatically</string>
|
||||
<string name="no_space">No space left for game files, please free space in the memory</string>
|
||||
<string name="ok" translatable="false">OK</string>
|
||||
|
||||
<!-- permission block -->
|
||||
<string name="explain">Storage permissions is necessary to unpack textures and game data.</string>
|
||||
<string name="location">Location permission provide you better interaction with game</string>
|
||||
<string name="close_game">Close game</string>
|
||||
<string name="settings">App settings</string>
|
||||
<string name="denied">You cannot play MultiCraft without storage permission.\nPlease turn on it at [Settings] -> [Permissions]></string>
|
||||
|
||||
<!-- rate dialog -->
|
||||
<string name="rate_dialog_title">Please, rate MultiCraft!</string>
|
||||
<string name="rate_description">Describe your experience</string>
|
||||
<string name="rate_submit">SUBMIT</string>
|
||||
<string name="sad">We are sorry that you did not like the game!</string>
|
||||
<string name="thank">Please leave a review for us. Thank you!</string>
|
||||
|
||||
<string name="recommend">Loading\nrecommendation\nfor you:\n%d sec.</string>
|
||||
|
||||
<!-- update dialog -->
|
||||
<string name="available">New Version Available!</string>
|
||||
<string name="update">Update</string>
|
||||
<string name="later">Later</string>
|
||||
<string name="ignore">Ignore</string>
|
||||
|
||||
<!-- no connection dialog -->
|
||||
<string name="conn_message">MultiCraft requires an internet connection to use all game features.\nOtherwise, you will not get updates and multiplayer will be not available!</string>
|
||||
<string name="conn_wifi" translatable="false">Wi-Fi</string>
|
||||
<string name="conn_mobile">Mobile Data</string>
|
||||
|
||||
<!-- uninstall old version dialog -->
|
||||
<string name="del_message">Uninstall an old version of MultiCraft?</string>
|
||||
|
||||
<!-- GDPR -->
|
||||
<string name="gdpr_main_text" translatable="false"><b>We care about your privacy and data security. We keep this app free by showing ads.\n<big>Can we continue to use your data to tailor ads for you?</big></b>\n\n<small>Our partners will collect data and use a unique identifier on your device to show you ads. By agreeing, you confirm that you are 16 years old. You can learn how we and our partners collect and use data on <a href="https://www.appodeal.com/privacy-policy">Privacy Policy</a>.</small></string>
|
||||
<string name="gdpr_agree" translatable="false">Yes, I allow</string>
|
||||
<string name="gdpr_disagree" translatable="false">No</string>
|
||||
|
||||
</resources>
|
||||
|
@ -3,20 +3,20 @@
|
||||
|
||||
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="android:windowFullscreen">true</item>
|
||||
<item name="android:windowBackground">@drawable/bg</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode" tools:targetApi="p">shortEdges</item>
|
||||
<item name="android:windowFullscreen">true</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode" tools:targetApi="p">shortEdges
|
||||
</item>
|
||||
</style>
|
||||
|
||||
<style name="InputTheme" parent="Theme.AppCompat.DayNight.Dialog">
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<style name="RateMe" parent="Theme.AppCompat.Light.Dialog">
|
||||
<item name="colorControlActivated">#008c80</item>
|
||||
<item name="android:windowBackground">@drawable/custom_dialog_rounded</item>
|
||||
</style>
|
||||
|
||||
<style name="CustomProgressBar" parent="@style/Widget.AppCompat.ProgressBar.Horizontal">
|
||||
<style name="CustomProgressBar" parent="Widget.AppCompat.ProgressBar.Horizontal">
|
||||
<item name="android:indeterminateOnly">false</item>
|
||||
<item name="android:minHeight">10dip</item>
|
||||
<item name="android:maxHeight">20dip</item>
|
||||
<item name="android:progressDrawable">@drawable/custom_progress_bar</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
12
build/android/app/src/main/res/xml/backup_rules.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<full-backup-content>
|
||||
<exclude
|
||||
domain="sharedpref"
|
||||
path="MultiCraftSettings.xml" />
|
||||
<exclude
|
||||
domain="sharedpref"
|
||||
path="RateMe.xml" />
|
||||
<exclude
|
||||
domain="sharedpref"
|
||||
path="com.multicraft.game_preferences.xml" />
|
||||
</full-backup-content>
|
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<base-config cleartextTrafficPermitted="true">
|
||||
<trust-anchors>
|
||||
<certificates src="system" />
|
||||
<certificates src="user" />
|
||||
</trust-anchors>
|
||||
</base-config>
|
||||
<domain-config cleartextTrafficPermitted="true">
|
||||
<domain includeSubdomains="true">127.0.0.1</domain>
|
||||
</domain-config>
|
||||
</network-security-config>
|
@ -1,10 +1,10 @@
|
||||
// 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", 3) // Version Minor
|
||||
project.ext.set("versionMajor", 2) // Version Major
|
||||
project.ext.set("versionMinor", 0) // Version Minor
|
||||
project.ext.set("versionPatch", 0) // Version Patch
|
||||
project.ext.set("versionExtra", "-dev") // Version Extra
|
||||
project.ext.set("versionCode", 30) // Android Version Code
|
||||
project.ext.set("versionExtra", "") // Version Extra
|
||||
project.ext.set("versionCode", 100) // 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
|
||||
@ -15,8 +15,10 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.6.3'
|
||||
classpath 'org.ajoberstar.grgit:grgit-gradle:4.0.2'
|
||||
classpath 'com.android.tools.build:gradle:4.1.2'
|
||||
//noinspection GradleDynamicVersion
|
||||
/*classpath 'com.bugsnag:bugsnag-android-gradle-plugin:5.+'*/
|
||||
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
|
||||
}
|
||||
@ -31,4 +33,5 @@ allprojects {
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
delete 'native/deps'
|
||||
}
|
||||
|
BIN
build/android/gradle/wrapper/gradle-wrapper.jar
vendored
@ -1,2 +1,6 @@
|
||||
#Mon Apr 06 00:06:16 CEST 2020
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
||||
#Fri Feb 12 19:20:09 CET 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
@ -1,16 +1,18 @@
|
||||
apply plugin: 'com.android.library'
|
||||
import org.ajoberstar.grgit.Grgit
|
||||
apply plugin: 'de.undercouch.download'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion '29.0.3'
|
||||
ndkVersion '21.1.6352462'
|
||||
buildToolsVersion '30.0.3'
|
||||
ndkVersion '22.0.7026061'
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
//noinspection OldTargetApi
|
||||
targetSdkVersion 29
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments '-j8',
|
||||
arguments '-j' + Runtime.getRuntime().availableProcessors(),
|
||||
"--output-sync=none",
|
||||
"versionMajor=${versionMajor}",
|
||||
"versionMinor=${versionMinor}",
|
||||
"versionPatch=${versionPatch}",
|
||||
@ -45,15 +47,49 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
task cloneGitRepo() {
|
||||
def destination = file('deps')
|
||||
if(!destination.exists()) {
|
||||
def grgit = Grgit.clone(
|
||||
dir: destination,
|
||||
uri: 'https://github.com/minetest/minetest_android_deps_binaries'
|
||||
)
|
||||
grgit.close()
|
||||
// get precompiled deps
|
||||
task downloadDeps(type: Download) {
|
||||
src 'https://github.com/MultiCraft/deps/archive/master.zip'
|
||||
dest new File(buildDir, 'deps.zip')
|
||||
overwrite false
|
||||
}
|
||||
|
||||
task getDeps(dependsOn: downloadDeps, type: Copy) {
|
||||
def deps = file('deps')
|
||||
def f = file("$buildDir/deps-master")
|
||||
|
||||
if (!f.exists()) {
|
||||
from zipTree(downloadDeps.dest)
|
||||
into buildDir
|
||||
}
|
||||
|
||||
doLast {
|
||||
file(f).renameTo(file(deps))
|
||||
}
|
||||
}
|
||||
|
||||
preBuild.dependsOn cloneGitRepo
|
||||
// get libiconv
|
||||
task downloadIconv(dependsOn: getDeps, type: Download) {
|
||||
src 'https://github.com/MoNTE48/ndk_iconv/archive/mc.zip'
|
||||
dest new File(buildDir, 'iconv.zip')
|
||||
overwrite false
|
||||
}
|
||||
|
||||
task getIconv(dependsOn: downloadIconv, type: Copy) {
|
||||
def iconv = file('deps/Android/ndk_iconv')
|
||||
def f = file("$buildDir/ndk_iconv-mc")
|
||||
|
||||
if (!iconv.exists() && !f.exists()) {
|
||||
from zipTree(downloadIconv.dest)
|
||||
into buildDir
|
||||
}
|
||||
|
||||
doLast {
|
||||
if (!iconv.exists()) {
|
||||
file(f).renameTo(file(iconv))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
preBuild.dependsOn getDeps
|
||||
preBuild.dependsOn getIconv
|
||||
|
@ -17,10 +17,10 @@ LOCAL_MODULE := Irrlicht
|
||||
LOCAL_SRC_FILES := deps/Android/Irrlicht/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libIrrlicht.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 := LevelDB
|
||||
LOCAL_SRC_FILES := deps/Android/LevelDB/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libleveldb.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := LuaJIT
|
||||
@ -59,13 +59,18 @@ include $(PREBUILT_STATIC_LIBRARY)
|
||||
#LOCAL_SRC_FILES := deps/Android/OpenSSL/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libcrypto.a
|
||||
#include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := Gettext
|
||||
LOCAL_SRC_FILES := deps/Android/Gettext/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libintl.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := Vorbis
|
||||
LOCAL_SRC_FILES := deps/Android/Vorbis/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libvorbis.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := Minetest
|
||||
LOCAL_MODULE := MultiCraft
|
||||
|
||||
LOCAL_CFLAGS += \
|
||||
-DJSONCPP_NO_LOCALE_SUPPORT \
|
||||
@ -74,8 +79,10 @@ LOCAL_CFLAGS += \
|
||||
-DUSE_CURL=1 \
|
||||
-DUSE_SOUND=1 \
|
||||
-DUSE_FREETYPE=1 \
|
||||
-DUSE_LEVELDB=0 \
|
||||
-DUSE_LEVELDB=1 \
|
||||
-DUSE_SQLITE=0 \
|
||||
-DUSE_LUAJIT=1 \
|
||||
-DUSE_GETTEXT=1 \
|
||||
-DVERSION_MAJOR=${versionMajor} \
|
||||
-DVERSION_MINOR=${versionMinor} \
|
||||
-DVERSION_PATCH=${versionPatch} \
|
||||
@ -101,11 +108,10 @@ LOCAL_C_INCLUDES := \
|
||||
deps/Android/Freetype/include \
|
||||
deps/Android/Irrlicht/include \
|
||||
deps/Android/LevelDB/include \
|
||||
deps/Android/libiconv/include \
|
||||
deps/Android/libiconv/libcharset/include \
|
||||
deps/Android/Gettext/include \
|
||||
deps/Android/ndk_iconv \
|
||||
deps/Android/LuaJIT/src \
|
||||
deps/Android/OpenAL-Soft/include \
|
||||
deps/Android/sqlite \
|
||||
deps/Android/Vorbis/include
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
@ -115,13 +121,44 @@ LOCAL_SRC_FILES := \
|
||||
../../../src/database/database.cpp \
|
||||
../../../src/database/database-dummy.cpp \
|
||||
../../../src/database/database-files.cpp \
|
||||
../../../src/database/database-sqlite3.cpp \
|
||||
../../../src/database/database-leveldb.cpp \
|
||||
$(wildcard ../../../src/gui/*.cpp) \
|
||||
$(wildcard ../../../src/irrlicht_changes/*.cpp) \
|
||||
$(wildcard ../../../src/mapgen/*.cpp) \
|
||||
$(wildcard ../../../src/network/*.cpp) \
|
||||
$(wildcard ../../../src/script/*.cpp) \
|
||||
$(wildcard ../../../src/script/*/*.cpp) \
|
||||
$(wildcard ../../../src/script/common/*.cpp) \
|
||||
$(wildcard ../../../src/script/cpp_api/*.cpp) \
|
||||
../../../src/script/lua_api/l_areastore.cpp \
|
||||
../../../src/script/lua_api/l_auth.cpp \
|
||||
../../../src/script/lua_api/l_base.cpp \
|
||||
../../../src/script/lua_api/l_camera.cpp \
|
||||
../../../src/script/lua_api/l_craft.cpp \
|
||||
../../../src/script/lua_api/l_client.cpp \
|
||||
../../../src/script/lua_api/l_env.cpp \
|
||||
../../../src/script/lua_api/l_http.cpp \
|
||||
../../../src/script/lua_api/l_inventory.cpp \
|
||||
../../../src/script/lua_api/l_item.cpp \
|
||||
../../../src/script/lua_api/l_itemstackmeta.cpp \
|
||||
../../../src/script/lua_api/l_localplayer.cpp \
|
||||
../../../src/script/lua_api/l_mainmenu.cpp \
|
||||
../../../src/script/lua_api/l_mapgen.cpp \
|
||||
../../../src/script/lua_api/l_metadata.cpp \
|
||||
../../../src/script/lua_api/l_minimap.cpp \
|
||||
../../../src/script/lua_api/l_modchannels.cpp \
|
||||
../../../src/script/lua_api/l_nodemeta.cpp \
|
||||
../../../src/script/lua_api/l_nodetimer.cpp \
|
||||
../../../src/script/lua_api/l_noise.cpp \
|
||||
../../../src/script/lua_api/l_object.cpp \
|
||||
../../../src/script/lua_api/l_particles.cpp \
|
||||
../../../src/script/lua_api/l_particles_local.cpp \
|
||||
../../../src/script/lua_api/l_playermeta.cpp \
|
||||
../../../src/script/lua_api/l_server.cpp \
|
||||
../../../src/script/lua_api/l_settings.cpp \
|
||||
../../../src/script/lua_api/l_sound.cpp \
|
||||
../../../src/script/lua_api/l_storage.cpp \
|
||||
../../../src/script/lua_api/l_util.cpp \
|
||||
../../../src/script/lua_api/l_vmanip.cpp \
|
||||
$(wildcard ../../../src/server/*.cpp) \
|
||||
$(wildcard ../../../src/threading/*.cpp) \
|
||||
$(wildcard ../../../src/util/*.c) \
|
||||
@ -173,8 +210,6 @@ LOCAL_SRC_FILES := \
|
||||
../../../src/raycast.cpp \
|
||||
../../../src/reflowscan.cpp \
|
||||
../../../src/remoteplayer.cpp \
|
||||
../../../src/rollback.cpp \
|
||||
../../../src/rollback_interface.cpp \
|
||||
../../../src/serialization.cpp \
|
||||
../../../src/server.cpp \
|
||||
../../../src/serverenvironment.cpp \
|
||||
@ -189,8 +224,6 @@ 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
|
||||
@ -198,16 +231,7 @@ 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 android_native_app_glue $(PROFILER_LIBS) #LevelDB
|
||||
#OpenSSL Crypto
|
||||
LOCAL_STATIC_LIBRARIES += Curl Gettext Freetype Irrlicht LevelDB OpenAL mbedTLS mbedx509 mbedcrypto Vorbis LuaJIT android_native_app_glue $(PROFILER_LIBS)
|
||||
|
||||
LOCAL_LDLIBS := -lEGL -lGLESv1_CM -lGLESv2 -landroid -lOpenSLES
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
APP_PLATFORM := ${APP_PLATFORM}
|
||||
APP_ABI := ${TARGET_ABI}
|
||||
APP_STL := c++_shared
|
||||
APP_STL := c++_static
|
||||
NDK_TOOLCHAIN_VERSION := clang
|
||||
APP_SHORT_COMMANDS := true
|
||||
APP_MODULES := Minetest
|
||||
APP_MODULES := MultiCraft
|
||||
|
||||
APP_CPPFLAGS := -Ofast -fvisibility=hidden -fexceptions -Wno-deprecated-declarations -Wno-extra-tokens
|
||||
APP_CPPFLAGS := -Ofast -fvisibility=hidden -Wno-extra-tokens
|
||||
|
||||
ifeq ($(APP_ABI),armeabi-v7a)
|
||||
APP_CPPFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb
|
||||
@ -16,17 +16,21 @@ endif
|
||||
#endif
|
||||
|
||||
ifndef NDEBUG
|
||||
APP_CPPFLAGS := -g -D_DEBUG -O0 -fno-omit-frame-pointer -fexceptions
|
||||
APP_CPPFLAGS := -g -D_DEBUG -O0 -fno-omit-frame-pointer
|
||||
endif
|
||||
|
||||
APP_CFLAGS := $(APP_CPPFLAGS) -Wno-parentheses-equality #-Werror=shorten-64-to-32
|
||||
APP_CPPFLAGS += -fexceptions #-Werror=shorten-64-to-32
|
||||
|
||||
# Silence Irrlicht warnings. Comment out with real debugging!
|
||||
APP_CPPFLAGS += -Wno-deprecated-declarations -Wno-inconsistent-missing-override
|
||||
|
||||
APP_CFLAGS := $(APP_CPPFLAGS)
|
||||
APP_CXXFLAGS := $(APP_CPPFLAGS) -frtti -std=gnu++17
|
||||
APP_LDFLAGS := -Wl,--no-warn-mismatch,--gc-sections,--icf=safe
|
||||
|
||||
ifeq ($(APP_ABI),arm64-v8a)
|
||||
APP_LDFLAGS := -Wl,--no-warn-mismatch,--gc-sections
|
||||
endif
|
||||
|
||||
ifndef NDEBUG
|
||||
ifdef NDEBUG
|
||||
APP_LDFLAGS := -Wl,--gc-sections,--icf=all
|
||||
else
|
||||
APP_LDFLAGS :=
|
||||
endif
|
||||
|
||||
APP_LDFLAGS += -fuse-ld=lld
|
||||
|
@ -1 +1 @@
|
||||
<manifest package="net.minetest" />
|
||||
<manifest package="com.multicraft" />
|
||||
|
@ -1,2 +1,2 @@
|
||||
rootProject.name = "Minetest"
|
||||
rootProject.name = "MultiCraft"
|
||||
include ':app', ':native'
|
||||
|