Try to implement write permission checking and requesting permissions on newer Android devices
This commit is contained in:
parent
139972e5c8
commit
ea60581142
4 changed files with 251 additions and 163 deletions
|
@ -61,12 +61,12 @@
|
|||
|
||||
<string name="write_failed">Write test has failed</string>
|
||||
|
||||
<string name="ask_about_new_basedir_msg">Move your game files somewhere else, for example Android/data/%s or internal memory. At next run I will ask you about folder again.</string>
|
||||
<string name="ask_about_new_basedir_msg">Move your game files somewhere else, for example Android/data/in.celest.xash3d.hl or internal memory. At next run I will ask you about folder again.</string>
|
||||
<string name="lollipop_request_permission_msg">Due to writing politics of newer Android versions, you need to select a root folder of storage where game data is located.</string>
|
||||
<string name="lollipop_select_folder_btn">Select folder</string>
|
||||
|
||||
<!-- These strings must be concat with a "ask_about_new_basedir" string -->
|
||||
<string name="lollipop_request_permission_fail_msg">Write test has been failed twice. </string>
|
||||
<string name="kitkat_write_fail_msg">Due to writing politics of Android 4.4, you can't use this storage. </string>
|
||||
<string name="kitkat_write_fail_msg">Due to writing politics of Android 4.4, you can\'t use this storage. </string>
|
||||
<string name="readonly_fs_fail_msg">Seems you have read-only filesystem. </string>
|
||||
</resources>
|
||||
|
|
72
src/in/celest/xash3d/CertCheck.java
Normal file
72
src/in/celest/xash3d/CertCheck.java
Normal file
|
@ -0,0 +1,72 @@
|
|||
package in.celest.xash3d;
|
||||
|
||||
import android.content.*;
|
||||
import android.view.*;
|
||||
import android.os.*;
|
||||
import android.util.*;
|
||||
import android.graphics.*;
|
||||
import android.text.method.*;
|
||||
import android.text.*;
|
||||
import android.media.*;
|
||||
import android.hardware.*;
|
||||
import android.content.*;
|
||||
import android.widget.*;
|
||||
import android.content.pm.*;
|
||||
|
||||
import java.lang.*;
|
||||
import java.util.List;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
import in.celest.xash3d.hl.BuildConfig;
|
||||
import in.celest.xash3d.XashConfig;
|
||||
|
||||
public class CertCheck
|
||||
{
|
||||
// Certificate checking
|
||||
private static String SIG = "DMsE8f5hlR7211D8uehbFpbA0n8=";
|
||||
private static String SIG_TEST = ""; // a1ba: mittorn, add your signature later
|
||||
|
||||
private static String TAG = "XASH3D:CertCheck";
|
||||
|
||||
public static boolean dumbAntiPDALifeCheck( Context context )
|
||||
{
|
||||
if( BuildConfig.DEBUG ||
|
||||
!XashConfig.CHECK_SIGNATURES )
|
||||
return false; // disable checking for debug builds
|
||||
|
||||
try
|
||||
{
|
||||
PackageInfo info = context.getPackageManager()
|
||||
.getPackageInfo( context.getPackageName(), PackageManager.GET_SIGNATURES );
|
||||
|
||||
for( Signature signature: info.signatures )
|
||||
{
|
||||
MessageDigest md = MessageDigest.getInstance( "SHA" );
|
||||
final byte[] signatureBytes = signature.toByteArray();
|
||||
|
||||
md.update( signatureBytes );
|
||||
|
||||
final String curSIG = Base64.encodeToString( md.digest(), Base64.NO_WRAP );
|
||||
|
||||
if( XashConfig.PKG_TEST )
|
||||
{
|
||||
if( SIG_TEST.equals(curSIG) )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( SIG.equals(curSIG) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Log.e(TAG, "Please, don't resign our public release builds!");
|
||||
Log.e(TAG, "If you want to insert some features, rebuild package with ANOTHER package name from git repository.");
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -55,6 +55,7 @@ import org.json.*;
|
|||
|
||||
import in.celest.xash3d.hl.R;
|
||||
import in.celest.xash3d.XashActivity;
|
||||
import in.celest.xash3d.CertCheck;
|
||||
|
||||
public class LauncherActivity extends Activity {
|
||||
// public final static String ARGV = "in.celest.xash3d.MESSAGE";
|
||||
|
@ -89,7 +90,7 @@ public class LauncherActivity extends Activity {
|
|||
super.setTheme( 0x01030224 );
|
||||
else super.setTheme( 0x01030005 );
|
||||
|
||||
if( XashActivity.dumbAntiPDALifeCheck( this ) )
|
||||
if( CertCheck.dumbAntiPDALifeCheck( this ) )
|
||||
{
|
||||
finish();
|
||||
return;
|
||||
|
|
|
@ -19,6 +19,9 @@ import android.hardware.*;
|
|||
import android.content.*;
|
||||
import android.widget.*;
|
||||
import android.content.pm.*;
|
||||
import android.net.Uri;
|
||||
import android.provider.*;
|
||||
import android.database.*;
|
||||
|
||||
import android.view.inputmethod.*;
|
||||
|
||||
|
@ -26,9 +29,11 @@ import java.lang.*;
|
|||
import java.util.List;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
import in.celest.xash3d.hl.R;
|
||||
import in.celest.xash3d.hl.BuildConfig;
|
||||
import in.celest.xash3d.XashConfig;
|
||||
import in.celest.xash3d.JoystickHandler;
|
||||
import in.celest.xash3d.CertCheck;
|
||||
|
||||
/**
|
||||
Xash Activity
|
||||
|
@ -47,12 +52,15 @@ public class XashActivity extends Activity {
|
|||
public static JoystickHandler handler;
|
||||
public static ImmersiveMode mImmersiveMode;
|
||||
public static boolean keyboardVisible = false;
|
||||
public static boolean mEngineReady = false;
|
||||
|
||||
private static Vibrator mVibrator;
|
||||
private static boolean mHasVibrator;
|
||||
private int mReturingWithResultCode = 0;
|
||||
|
||||
private static int OPEN_DOCUMENT_TREE_RESULT = 1;
|
||||
private static int FPICKER_RESULT = 2;
|
||||
|
||||
|
||||
// Joystick constants
|
||||
public final static byte JOY_HAT_CENTERED = 0; // bitmasks for hat current status
|
||||
|
@ -73,9 +81,6 @@ public class XashActivity extends Activity {
|
|||
private static boolean mUseVolume;
|
||||
public static View mDecorView;
|
||||
|
||||
// Certificate checking
|
||||
private static String SIG = "DMsE8f5hlR7211D8uehbFpbA0n8=";
|
||||
private static String SIG_TEST = ""; // a1ba: mittorn, add your signature later
|
||||
|
||||
// Load the .so
|
||||
static {
|
||||
|
@ -83,56 +88,15 @@ public class XashActivity extends Activity {
|
|||
System.loadLibrary("xash");
|
||||
}
|
||||
|
||||
// Shared between this activity and LauncherActivity
|
||||
public static boolean dumbAntiPDALifeCheck( Context context )
|
||||
{
|
||||
if( BuildConfig.DEBUG ||
|
||||
!XashConfig.CHECK_SIGNATURES )
|
||||
return false; // disable checking for debug builds
|
||||
|
||||
try
|
||||
{
|
||||
PackageInfo info = context.getPackageManager()
|
||||
.getPackageInfo( context.getPackageName(), PackageManager.GET_SIGNATURES );
|
||||
|
||||
for( Signature signature: info.signatures )
|
||||
{
|
||||
MessageDigest md = MessageDigest.getInstance( "SHA" );
|
||||
final byte[] signatureBytes = signature.toByteArray();
|
||||
|
||||
md.update( signatureBytes );
|
||||
|
||||
final String curSIG = Base64.encodeToString( md.digest(), Base64.NO_WRAP );
|
||||
|
||||
if( XashConfig.PKG_TEST )
|
||||
{
|
||||
if( SIG_TEST.equals(curSIG) )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( SIG.equals(curSIG) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Log.e(TAG, "Please, don't resign our public release builds!");
|
||||
Log.e(TAG, "If you want to insert some features, rebuild package with ANOTHER package name from git repository.");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Setup
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
Log.v(TAG, "onCreate()");
|
||||
super.onCreate(savedInstanceState);
|
||||
mEngineReady = false;
|
||||
|
||||
if( dumbAntiPDALifeCheck(this) )
|
||||
if( CertCheck.dumbAntiPDALifeCheck(this) )
|
||||
{
|
||||
finish();
|
||||
return;
|
||||
|
@ -170,27 +134,6 @@ public class XashActivity extends Activity {
|
|||
checkWritePermission( basedir );
|
||||
}
|
||||
|
||||
|
||||
if( sdk < 12 )
|
||||
handler = new JoystickHandler();
|
||||
else
|
||||
handler = new JoystickHandler_v12();
|
||||
handler.init();
|
||||
|
||||
mPixelFormat = mPref.getInt("pixelformat", 0);
|
||||
mUseVolume = mPref.getBoolean("usevolume", false);
|
||||
if( mPref.getBoolean("enableResizeWorkaround", true) )
|
||||
AndroidBug5497Workaround.assistActivity(this);
|
||||
|
||||
// Immersive Mode is available only at >KitKat
|
||||
Boolean enableImmersive = (sdk >= 19) && (mPref.getBoolean("immersive_mode", true));
|
||||
if( enableImmersive )
|
||||
mImmersiveMode = new ImmersiveMode_v19();
|
||||
|
||||
mDecorView = getWindow().getDecorView();
|
||||
|
||||
mVibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
|
||||
mHasVibrator = ( mVibrator != null ) && ( mVibrator.hasVibrator() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -198,43 +141,145 @@ public class XashActivity extends Activity {
|
|||
{
|
||||
if( resultCode != RESULT_OK )
|
||||
{
|
||||
Log.v(TAG, "onActivityResult: result is not OK. Code: " + requestCode + ". Will exit now");
|
||||
finish();
|
||||
Log.v(TAG, "onActivityResult: result is not OK. ReqCode: " + requestCode + ". ResCode: " + resultCode);
|
||||
}
|
||||
|
||||
if( requestCode == FPICKER_RESULT )
|
||||
else
|
||||
{
|
||||
String newBaseDir = resultData.getStringExtra("GetPath");
|
||||
setNewBasedir( newBaseDir );
|
||||
setFolderAsk( false ); // don't ask on next run
|
||||
checkWritePermission( newBaseDir );
|
||||
}
|
||||
else if( requestCode == OPEN_DOCUMENT_TREE_RESULT )
|
||||
{
|
||||
String basedir = getStringExtraFromIntent( getIntent(), "basedir", mPref.getString("basedir","/sdcard/xash/"));
|
||||
|
||||
if( !nativeTestWritePermission( basedir ) )
|
||||
// it's not possible to create dialogs here
|
||||
// so most work will be done after Activity resuming, in onPostResume()
|
||||
mReturingWithResultCode = requestCode;
|
||||
if( requestCode == FPICKER_RESULT )
|
||||
{
|
||||
String msg = getString(R.string.lollipop_request_permission_fail_msg) + getString(R.string.ask_about_new_basedir_msg);
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle( R.string.write_failed )
|
||||
.setMessage( msg )
|
||||
.setPositiveButton( R.string.ok, new DialogInterface.OnClickListener()
|
||||
{
|
||||
public void onClick(DialogInterface dialog, int whichButton)
|
||||
{
|
||||
XashActivity act = (XashActivity)getActivity();
|
||||
act.setFolderAsk( true );
|
||||
act.finish();
|
||||
}
|
||||
})
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
String newBaseDir = resultData.getStringExtra("GetPath");
|
||||
setNewBasedir( newBaseDir );
|
||||
setFolderAsk( false ); // don't ask on next run
|
||||
Log.v(TAG, "Got new basedir from FPicker: " + newBaseDir );
|
||||
}
|
||||
else if( requestCode == OPEN_DOCUMENT_TREE_RESULT )
|
||||
{
|
||||
Uri uri = resultData.getData();
|
||||
if( uri != null )
|
||||
{
|
||||
getContentResolver().takePersistableUriPermission(uri,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostResume()
|
||||
{
|
||||
super.onPostResume();
|
||||
|
||||
if( mReturingWithResultCode != 0 )
|
||||
{
|
||||
if( mReturingWithResultCode == FPICKER_RESULT )
|
||||
{
|
||||
String basedir = mPref.getString( "basedir", "/sdcard/xash/" );
|
||||
checkWritePermission( basedir );
|
||||
}
|
||||
else if( mReturingWithResultCode == OPEN_DOCUMENT_TREE_RESULT )
|
||||
{
|
||||
String basedir = getStringExtraFromIntent( getIntent(), "basedir", mPref.getString("basedir","/sdcard/xash/"));
|
||||
Log.v(TAG, "Got permissions. Checking writing again...");
|
||||
|
||||
if( nativeTestWritePermission( basedir ) == 0 )
|
||||
{
|
||||
Log.v(TAG, "Write test has failed twice!");
|
||||
String msg = getString(R.string.lollipop_request_permission_fail_msg) + getString(R.string.ask_about_new_basedir_msg);
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle( R.string.write_failed )
|
||||
.setMessage( msg )
|
||||
.setPositiveButton( R.string.ok, new DialogInterface.OnClickListener()
|
||||
{
|
||||
public void onClick(DialogInterface dialog, int whichButton)
|
||||
{
|
||||
XashActivity act = XashActivity.this;
|
||||
act.setFolderAsk( true );
|
||||
act.finish();
|
||||
}
|
||||
})
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
}
|
||||
else
|
||||
{
|
||||
launchSurfaceAndEngine();
|
||||
}
|
||||
}
|
||||
|
||||
mReturingWithResultCode = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Events
|
||||
@Override
|
||||
protected void onPause() {
|
||||
Log.v(TAG, "onPause()");
|
||||
|
||||
if( mEngineReady )
|
||||
{
|
||||
// let engine save all configs before exiting.
|
||||
nativeOnPause();
|
||||
|
||||
// wait until Xash will save all configs
|
||||
mSurface.engineThreadWait();
|
||||
|
||||
}
|
||||
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
Log.v(TAG, "onResume()");
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
Log.v(TAG, "onStop()");
|
||||
|
||||
if( mEngineReady )
|
||||
{
|
||||
// let engine properly exit, instead of killing it's thread
|
||||
nativeOnStop();
|
||||
|
||||
// wait for engine
|
||||
mSurface.engineThreadWait();
|
||||
}
|
||||
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
Log.v(TAG, "onStop()");
|
||||
|
||||
if( mEngineReady )
|
||||
{
|
||||
// let engine a chance to properly exit
|
||||
nativeOnDestroy();
|
||||
|
||||
// wait until Xash will exit
|
||||
mSurface.engineThreadJoin();
|
||||
}
|
||||
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus)
|
||||
{
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
|
||||
if( mImmersiveMode != null )
|
||||
mImmersiveMode.apply();
|
||||
}
|
||||
|
||||
public void setFolderAsk( Boolean b )
|
||||
{
|
||||
SharedPreferences.Editor editor = mPref.edit();
|
||||
|
@ -247,7 +292,7 @@ public class XashActivity extends Activity {
|
|||
{
|
||||
SharedPreferences.Editor editor = mPref.edit();
|
||||
|
||||
editor.putBoolean( "basedir", baseDir );
|
||||
editor.putString( "basedir", baseDir );
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
|
@ -261,10 +306,12 @@ public class XashActivity extends Activity {
|
|||
|
||||
private void checkWritePermission( String basedir )
|
||||
{
|
||||
if( !nativeTestWritePermission( basedir ) )
|
||||
Log.v(TAG, "Checking write permissions...");
|
||||
|
||||
if( nativeTestWritePermission( basedir ) == 0 )
|
||||
{
|
||||
Object lock = new Object;
|
||||
|
||||
Log.v(TAG, "First check has failed!");
|
||||
|
||||
if( sdk > 20 )
|
||||
{
|
||||
// OPEN_DOCUMENT_TREE
|
||||
|
@ -278,8 +325,7 @@ public class XashActivity extends Activity {
|
|||
public void onClick(DialogInterface dialog, int whichButton)
|
||||
{
|
||||
Intent intent = new Intent("android.intent.action.OPEN_DOCUMENT_TREE");
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
getActivity().startActivityForResult(intent, OPEN_DOCUMENT_TREE_RESULT);
|
||||
XashActivity.this.startActivityForResult(intent, OPEN_DOCUMENT_TREE_RESULT);
|
||||
}
|
||||
})
|
||||
.setCancelable(false)
|
||||
|
@ -297,7 +343,7 @@ public class XashActivity extends Activity {
|
|||
{
|
||||
public void onClick(DialogInterface dialog, int whichButton)
|
||||
{
|
||||
XashActivity act = (XashActivity)getActivity();
|
||||
XashActivity act = XashActivity.this;
|
||||
act.setFolderAsk( true );
|
||||
act.finish();
|
||||
}
|
||||
|
@ -318,7 +364,7 @@ public class XashActivity extends Activity {
|
|||
{
|
||||
public void onClick(DialogInterface dialog, int whichButton)
|
||||
{
|
||||
XashActivity act = (XashActivity)getActivity();
|
||||
XashActivity act = XashActivity.this;
|
||||
act.setFolderAsk( true );
|
||||
act.finish();
|
||||
}
|
||||
|
@ -336,10 +382,11 @@ public class XashActivity extends Activity {
|
|||
|
||||
private void launchSurfaceAndEngine()
|
||||
{
|
||||
Log.v(TAG, "Everything is OK. Launching engine...");
|
||||
|
||||
setupEnvironment();
|
||||
InstallReceiver.extractPAK(this, false);
|
||||
|
||||
|
||||
// Set up the surface
|
||||
mSurface = new EngineSurface(getApplication());
|
||||
|
||||
|
@ -350,6 +397,28 @@ public class XashActivity extends Activity {
|
|||
SurfaceHolder holder = mSurface.getHolder();
|
||||
holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
|
||||
|
||||
if( sdk < 12 )
|
||||
handler = new JoystickHandler();
|
||||
else
|
||||
handler = new JoystickHandler_v12();
|
||||
handler.init();
|
||||
|
||||
mPixelFormat = mPref.getInt("pixelformat", 0);
|
||||
mUseVolume = mPref.getBoolean("usevolume", false);
|
||||
if( mPref.getBoolean("enableResizeWorkaround", true) )
|
||||
AndroidBug5497Workaround.assistActivity(this);
|
||||
|
||||
// Immersive Mode is available only at >KitKat
|
||||
Boolean enableImmersive = (sdk >= 19) && (mPref.getBoolean("immersive_mode", true));
|
||||
if( enableImmersive )
|
||||
mImmersiveMode = new ImmersiveMode_v19();
|
||||
|
||||
mDecorView = getWindow().getDecorView();
|
||||
|
||||
mVibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
|
||||
mHasVibrator = ( mVibrator != null ) && ( mVibrator.hasVibrator() );
|
||||
|
||||
mEngineReady = true;
|
||||
}
|
||||
|
||||
private void setupEnvironment()
|
||||
|
@ -390,61 +459,7 @@ public class XashActivity extends Activity {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Events
|
||||
@Override
|
||||
protected void onPause() {
|
||||
Log.v(TAG, "onPause()");
|
||||
|
||||
// let engine save all configs before exiting.
|
||||
nativeOnPause();
|
||||
|
||||
// wait until Xash will save all configs
|
||||
mSurface.engineThreadWait();
|
||||
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
Log.v(TAG, "onResume()");
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
Log.v(TAG, "onStop()");
|
||||
|
||||
// let engine properly exit, instead of killing it's thread
|
||||
nativeOnStop();
|
||||
|
||||
// wait for engine
|
||||
mSurface.engineThreadWait();
|
||||
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
Log.v(TAG, "onStop()");
|
||||
|
||||
// let engine a chance to properly exit
|
||||
nativeOnDestroy();
|
||||
|
||||
// wait until Xash will exit
|
||||
mSurface.engineThreadJoin();
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus)
|
||||
{
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
|
||||
if( mImmersiveMode != null )
|
||||
mImmersiveMode.apply();
|
||||
}
|
||||
|
||||
public static native int nativeInit(Object arguments);
|
||||
public static native void nativeQuit();
|
||||
|
|
Loading…
Add table
Reference in a new issue