Add storage unmount handling

+other fixes for crashes from gplay console
This commit is contained in:
artdeell 2023-02-27 22:17:00 +03:00
parent 98a098a397
commit a945d2bc01
12 changed files with 152 additions and 71 deletions

View File

@ -4,100 +4,105 @@
package="net.kdt.pojavlaunch">
<uses-feature android:glEsVersion="0x00020000" />
<uses-feature android:name="android.hardware.type.pc" android:required="false" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="28"/>
<uses-feature
android:name="android.hardware.type.pc"
android:required="false" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:allowBackup="true"
android:name=".PojavApplication"
android:theme="@style/AppTheme"
android:label="@string/app_name"
android:allowBackup="true"
android:allowNativeHeapPointerTagging="false"
android:appCategory="game"
android:hasFragileUserData="true"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:isGame="true"
android:label="@string/app_name"
android:process=":launcher"
android:resizeableActivity="true"
android:hasFragileUserData="true"
android:isGame="true"
android:appCategory="game"
android:allowNativeHeapPointerTagging="false">
android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/AppTheme">
<activity
android:name=".MissingStorageActivity"
android:exported="false" />
<meta-data
android:name="android.max_aspect"
android:value="ratio_float" />
<activity android:name=".TestStorageActivity"
<activity
android:name=".TestStorageActivity"
android:exported="true"
android:launchMode="singleTop"
android:label="@string/app_short_name">
android:label="@string/app_short_name"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:label="@string/app_short_name"
android:name=".LauncherActivity">
</activity>
android:name=".LauncherActivity"
android:label="@string/app_short_name" />
<activity
android:name=".ImportControlActivity"
android:exported="true"
android:windowSoftInputMode="stateVisible"
android:launchMode="singleInstance"
android:configChanges="keyboard|keyboardHidden"
>
<intent-filter android:scheme="content"
android:exported="true"
android:launchMode="singleInstance"
android:windowSoftInputMode="stateVisible">
<intent-filter
android:label="@string/import_control_label"
android:scheme="content"
tools:ignore="AppLinkUrlError">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/json" />
<data android:mimeType="text/json" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<activity
android:theme="@style/Theme.AppCompat.DayNight.Dialog"
android:screenOrientation="sensorLandscape"
android:name=".FatalErrorActivity"
android:configChanges="keyboardHidden|orientation|screenSize|keyboard|navigation"/>
android:configChanges="keyboardHidden|orientation|screenSize|keyboard|navigation"
android:theme="@style/Theme.AppCompat.DayNight.Dialog" />
<activity
android:theme="@style/Theme.AppCompat.DayNight.Dialog"
android:screenOrientation="sensorLandscape"
android:name=".ExitActivity"
android:configChanges="keyboardHidden|orientation|screenSize|keyboard|navigation"/>
android:configChanges="keyboardHidden|orientation|screenSize|keyboard|navigation"
android:theme="@style/Theme.AppCompat.DayNight.Dialog" />
<activity
android:screenOrientation="sensorLandscape"
android:name=".JavaGUILauncherActivity"
android:configChanges="keyboardHidden|orientation|screenSize|keyboard|navigation"/>
android:configChanges="keyboardHidden|orientation|screenSize|keyboard|navigation"
android:screenOrientation="sensorLandscape" />
<activity
android:screenOrientation="sensorLandscape"
android:name=".CustomControlsActivity"
android:configChanges="keyboardHidden|orientation|screenSize|keyboard|navigation"
android:exported="true">
android:exported="true"
android:screenOrientation="sensorLandscape">
<intent-filter>
<action android:name=".CustomControlsActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:process=":game"
android:launchMode="standard"
android:screenOrientation="sensorLandscape"
android:name=".MainActivity"
android:configChanges="keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|keyboard|navigation|uiMode"/>
android:configChanges="keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|keyboard|navigation|uiMode"
android:launchMode="standard"
android:process=":game"
android:screenOrientation="sensorLandscape" />
<provider
android:name=".scoped.FolderProvider"
@ -111,8 +116,9 @@
</provider>
<service android:name=".services.ProgressService" />
<service android:name=".services.GameService" android:process=":game"/>
<service
android:name=".services.GameService"
android:process=":game" />
</application>
</manifest>

View File

@ -34,6 +34,15 @@ public abstract class BaseActivity extends AppCompatActivity {
//new Throwable("StartActivity").printStackTrace();
}
@Override
protected void onResume() {
super.onResume();
if(!Tools.checkStorageRoot(this)) {
startActivity(new Intent(this, MissingStorageActivity.class));
finish();
}
}
@Override
protected void onPostResume() {
super.onPostResume();

View File

@ -67,6 +67,10 @@ public class ImportControlActivity extends Activity {
if(!mHasIntentChanged) return;
mIsFileVerified = false;
getUriData();
if(mUriData == null) {
finishAndRemoveTask();
return;
}
mEditText.setText(getNameFromURI(mUriData));
mHasIntentChanged = false;

View File

@ -0,0 +1,13 @@
package net.kdt.pojavlaunch;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MissingStorageActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.storage_test_no_sdcard);
}
}

View File

@ -28,8 +28,8 @@ public class PojavApplication extends Application {
@Override
public void onCreate() {
Thread.setDefaultUncaughtExceptionHandler((thread, th) -> {
boolean storagePermAllowed = Build.VERSION.SDK_INT < 23 || Build.VERSION.SDK_INT >= 29 ||
ActivityCompat.checkSelfPermission(PojavApplication.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
boolean storagePermAllowed = (Build.VERSION.SDK_INT < 23 || Build.VERSION.SDK_INT >= 29 ||
ActivityCompat.checkSelfPermission(PojavApplication.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) && Tools.checkStorageRoot(PojavApplication.this);
File crashFile = new File(storagePermAllowed ? Tools.DIR_GAME_HOME : Tools.DIR_DATA, "latestcrash.txt");
try {
// Write to file, since some devices may not able to show error

View File

@ -56,6 +56,10 @@ public class TestStorageActivity extends Activity {
}
private void exit() {
if(!Tools.checkStorageRoot(this)) {
startActivity(new Intent(this, MissingStorageActivity.class));
return;
}
//Only run them once we get a definitive green light to use storage
AsyncAssetManager.unpackComponents(this);
AsyncAssetManager.unpackSingleFiles(this);

View File

@ -86,6 +86,26 @@ public final class Tools {
public static final String LIBNAME_OPTIFINE = "optifine:OptiFine";
public static final int RUN_MOD_INSTALLER = 2050;
private static File getPojavStorageRoot(Context ctx) {
if(SDK_INT >= 29) {
return ctx.getExternalFilesDir(null);
}else{
return new File(Environment.getExternalStorageDirectory(),"games/PojavLauncher");
}
}
/**
* Checks if the Pojav's storage root is accessible and read-writable
* @param context context to get the storage root if it's not set yet
* @return true if storage is fine, false if storage is not accessible
*/
public static boolean checkStorageRoot(Context context) {
File externalFilesDir = DIR_GAME_HOME == null ? Tools.getPojavStorageRoot(context) : new File(DIR_GAME_HOME);
//externalFilesDir == null when the storage is not mounted if it was obtained with the context call
return externalFilesDir != null && Environment.getExternalStorageState(externalFilesDir).equals(Environment.MEDIA_MOUNTED);
}
/**
* Since some constant requires the use of the Context object
* You can call this function to initialize them.
@ -94,11 +114,7 @@ public final class Tools {
public static void initContextConstants(Context ctx){
DIR_DATA = ctx.getFilesDir().getParent();
MULTIRT_HOME = DIR_DATA+"/runtimes";
if(SDK_INT >= 29) {
DIR_GAME_HOME = ctx.getExternalFilesDir(null).getAbsolutePath();
}else{
DIR_GAME_HOME = new File(Environment.getExternalStorageDirectory(),"games/PojavLauncher").getAbsolutePath();
}
DIR_GAME_HOME = getPojavStorageRoot(ctx).getAbsolutePath();
DIR_GAME_NEW = DIR_GAME_HOME + "/.minecraft";
DIR_HOME_VERSION = DIR_GAME_NEW + "/versions";
DIR_HOME_LIBRARY = DIR_GAME_NEW + "/libraries";

View File

@ -161,7 +161,7 @@ public class MultiRTUtils {
public static Runtime read(String name) {
if(sCache.containsKey(name)) return sCache.get(name);
Runtime returnRuntime;
File release = new File(RUNTIME_FOLDER,"/"+name+"/release");
File release = new File(RUNTIME_FOLDER,name+"/release");
if(!release.exists()) {
return new Runtime(name);
}

View File

@ -0,0 +1,5 @@
<vector android:height="@dimen/_128sdp" android:tint="@color/primary_text"
android:viewportHeight="24" android:viewportWidth="24"
android:width="@dimen/_128sdp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M18,2h-8L4.02,8L4,20c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C20,2.9 19.1,2 18,2zM13,17h-2v-2h2V17zM13,13h-2V8h2V13z"/>
</vector>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="@dimen/_128sdp"
android:layout_height="@dimen/_128sdp"
android:adjustViewBounds="true"
android:src="@drawable/storage_alert" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="@dimen/_8sdp"
android:paddingTop="@dimen/_10sdp"
android:paddingEnd="@dimen/_8sdp"
android:text="@string/storage_required" />
</LinearLayout>

View File

@ -349,4 +349,5 @@
<string name="preference_gyro_sample_rate_title">Gyroscope sampling rate</string>
<string name="preference_gyro_sample_rate_description">If you have performance issues with the gyroscope controls, increase this</string>
<string name="microsoft_login_retry_later">Too many requests, please try again later.</string>
<string name="storage_required">PojavLauncher requires an attached external storage. Please reconnect your storage and restart the app.</string>
</resources>

View File

@ -10,7 +10,7 @@
android:summary="@string/preference_edit_controls_summary"
app2:icon="@drawable/ic_menu_custom_controls"
>
<intent android:action=".CustomControlsActivity"/>
<intent android:targetPackage="net.kdt.pojavlaunch" android:targetClass="net.kdt.pojavlaunch.CustomControlsActivity"/>
</Preference>
<PreferenceCategory