android: delay loading of RetroActivity until after permissions are granted

This commit is contained in:
Brad Parker 2017-06-14 20:19:52 +00:00
parent 39ea7deef7
commit d5a1ad0a73
4 changed files with 147 additions and 142 deletions

View File

@ -1500,11 +1500,6 @@ static void frontend_linux_get_env(int *argc,
__android_log_print(ANDROID_LOG_INFO, __android_log_print(ANDROID_LOG_INFO,
"RetroArch", "[ENV]: app dir: [%s]\n", app_dir); "RetroArch", "[ENV]: app dir: [%s]\n", app_dir);
/* Check for runtime permissions on Android 6.0+ */
if (env && android_app->checkRuntimePermissions)
CALL_VOID_METHOD(env, android_app->activity->clazz,
android_app->checkRuntimePermissions);
/* set paths depending on the ability to write /* set paths depending on the ability to write
* to internal_storage_path */ * to internal_storage_path */
@ -1953,8 +1948,6 @@ static void frontend_linux_init(void *data)
"onRetroArchExit", "()V"); "onRetroArchExit", "()V");
GET_METHOD_ID(env, android_app->isAndroidTV, class, GET_METHOD_ID(env, android_app->isAndroidTV, class,
"isAndroidTV", "()Z"); "isAndroidTV", "()Z");
GET_METHOD_ID(env, android_app->checkRuntimePermissions, class,
"checkRuntimePermissions", "()V");
CALL_OBJ_METHOD(env, obj, android_app->activity->clazz, CALL_OBJ_METHOD(env, obj, android_app->activity->clazz,
android_app->getIntent); android_app->getIntent);

View File

@ -161,7 +161,6 @@ struct android_app
jmethodID getPendingIntentDownloadsLocation; jmethodID getPendingIntentDownloadsLocation;
jmethodID getPendingIntentScreenshotsLocation; jmethodID getPendingIntentScreenshotsLocation;
jmethodID isAndroidTV; jmethodID isAndroidTV;
jmethodID checkRuntimePermissions;
}; };

View File

@ -15,12 +15,158 @@ import android.preference.PreferenceActivity;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.provider.Settings; import android.provider.Settings;
import java.util.List;
import java.util.ArrayList;
import android.content.pm.PackageManager;
import android.Manifest;
import android.content.DialogInterface;
import android.app.AlertDialog;
import android.util.Log;
/** /**
* {@link PreferenceActivity} subclass that provides all of the * {@link PreferenceActivity} subclass that provides all of the
* functionality of the main menu screen. * functionality of the main menu screen.
*/ */
public final class MainMenuActivity extends PreferenceActivity public final class MainMenuActivity extends PreferenceActivity
{ {
final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124;
boolean checkPermissions = false;
public void showMessageOKCancel(String message, DialogInterface.OnClickListener onClickListener)
{
new AlertDialog.Builder(this).setMessage(message)
.setPositiveButton("OK", onClickListener).setCancelable(false)
.setNegativeButton("Cancel", null).create().show();
}
private boolean addPermission(List<String> permissionsList, String permission)
{
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED)
{
permissionsList.add(permission);
// Check for Rationale Option
if (!shouldShowRequestPermissionRationale(permission))
return false;
}
return true;
}
public void checkRuntimePermissions()
{
if (android.os.Build.VERSION.SDK_INT >= 23)
{
// Android 6.0+ needs runtime permission checks
List<String> permissionsNeeded = new ArrayList<String>();
final List<String> permissionsList = new ArrayList<String>();
if (!addPermission(permissionsList, Manifest.permission.READ_EXTERNAL_STORAGE))
permissionsNeeded.add("Read External Storage");
if (!addPermission(permissionsList, Manifest.permission.WRITE_EXTERNAL_STORAGE))
permissionsNeeded.add("Write External Storage");
if (permissionsList.size() > 0)
{
checkPermissions = true;
if (permissionsNeeded.size() > 0)
{
// Need Rationale
Log.i("MainMenuActivity", "Need to request external storage permissions.");
String message = "You need to grant access to " + permissionsNeeded.get(0);
for (int i = 1; i < permissionsNeeded.size(); i++)
message = message + ", " + permissionsNeeded.get(i);
showMessageOKCancel(message,
new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
if (which == AlertDialog.BUTTON_POSITIVE)
{
requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
Log.i("MainMenuActivity", "User accepted request for external storage permissions.");
}
}
});
}
else
{
requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
Log.i("MainMenuActivity", "Requested external storage permissions.");
}
}
}
if (!checkPermissions)
{
finalStartup();
}
}
public void finalStartup()
{
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
Intent retro;
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB))
{
retro = new Intent(this, RetroActivityFuture.class);
}
else
{
retro = new Intent(this, RetroActivityPast.class);
}
retro.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startRetroActivity(
retro,
null,
prefs.getString("libretro_path", getApplicationInfo().dataDir + "/cores/"),
UserPreferences.getDefaultConfigPath(this),
Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD),
getApplicationInfo().dataDir,
getApplicationInfo().sourceDir);
startActivity(retro);
finish();
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
{
switch (requestCode)
{
case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS:
for (int i = 0; i < permissions.length; i++)
{
if(grantResults[i] == PackageManager.PERMISSION_GRANTED)
{
Log.i("MainMenuActivity", "Permission: " + permissions[i] + " was granted.");
}
else
{
Log.i("MainMenuActivity", "Permission: " + permissions[i] + " was not granted.");
}
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
break;
}
finalStartup();
}
public static void startRetroActivity(Intent retro, String contentPath, String corePath, public static void startRetroActivity(Intent retro, String contentPath, String corePath,
String configFilePath, String imePath, String dataDirPath, String dataSourcePath) String configFilePath, String imePath, String dataDirPath, String dataSourcePath)
{ {
@ -48,28 +194,7 @@ public final class MainMenuActivity extends PreferenceActivity
setVolumeControlStream(AudioManager.STREAM_MUSIC); setVolumeControlStream(AudioManager.STREAM_MUSIC);
UserPreferences.updateConfigFile(this); UserPreferences.updateConfigFile(this);
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
Intent retro;
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)) checkRuntimePermissions();
{
retro = new Intent(this, RetroActivityFuture.class);
}
else
{
retro = new Intent(this, RetroActivityPast.class);
}
retro.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startRetroActivity(
retro,
null,
prefs.getString("libretro_path", getApplicationInfo().dataDir + "/cores/"),
UserPreferences.getDefaultConfigPath(this),
Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD),
getApplicationInfo().dataDir,
getApplicationInfo().sourceDir);
startActivity(retro);
finish();
} }
} }

View File

@ -1,23 +1,15 @@
package com.retroarch.browser.retroactivity; package com.retroarch.browser.retroactivity;
import java.util.List;
import java.util.ArrayList;
import com.retroarch.browser.preferences.util.UserPreferences; import com.retroarch.browser.preferences.util.UserPreferences;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.app.UiModeManager; import android.app.UiModeManager;
import android.util.Log; import android.util.Log;
import android.content.pm.PackageManager;
import android.Manifest;
import android.content.DialogInterface;
import android.app.AlertDialog;
/** /**
* Class which provides common methods for RetroActivity related classes. * Class which provides common methods for RetroActivity related classes.
*/ */
public class RetroActivityCommon extends RetroActivityLocation public class RetroActivityCommon extends RetroActivityLocation
{ {
final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124;
// Exiting cleanly from NDK seems to be nearly impossible. // Exiting cleanly from NDK seems to be nearly impossible.
// Have to use exit(0) to avoid weird things happening, even with runOnUiThread() approaches. // Have to use exit(0) to avoid weird things happening, even with runOnUiThread() approaches.
// Use a separate JNI function to explicitly trigger the readback. // Use a separate JNI function to explicitly trigger the readback.
@ -26,110 +18,6 @@ public class RetroActivityCommon extends RetroActivityLocation
finish(); finish();
} }
public void showMessageOKCancel(String message, DialogInterface.OnClickListener onClickListener)
{
new AlertDialog.Builder(this).setMessage(message)
.setPositiveButton("OK", onClickListener).setCancelable(false)
.setNegativeButton("Cancel", null).create().show();
}
private boolean addPermission(List<String> permissionsList, String permission)
{
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED)
{
permissionsList.add(permission);
// Check for Rationale Option
if (!shouldShowRequestPermissionRationale(permission))
return false;
}
return true;
}
public void checkRuntimePermissions()
{
runOnUiThread(new Runnable() {
public void run() {
checkRuntimePermissionsRunnable();
}
});
}
public void checkRuntimePermissionsRunnable()
{
if (android.os.Build.VERSION.SDK_INT >= 23)
{
// Android 6.0+ needs runtime permission checks
List<String> permissionsNeeded = new ArrayList<String>();
final List<String> permissionsList = new ArrayList<String>();
if (!addPermission(permissionsList, Manifest.permission.READ_EXTERNAL_STORAGE))
permissionsNeeded.add("Read External Storage");
if (!addPermission(permissionsList, Manifest.permission.WRITE_EXTERNAL_STORAGE))
permissionsNeeded.add("Write External Storage");
if (permissionsList.size() > 0)
{
if (permissionsNeeded.size() > 0)
{
// Need Rationale
Log.i("RetroActivity", "Need to request external storage permissions.");
String message = "You need to grant access to " + permissionsNeeded.get(0);
for (int i = 1; i < permissionsNeeded.size(); i++)
message = message + ", " + permissionsNeeded.get(i);
showMessageOKCancel(message,
new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
Log.i("RetroActivity", "User accepted request for external storage permissions.");
}
});
}
else
{
requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
Log.i("RetroActivity", "Requested external storage permissions.");
}
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
{
switch (requestCode)
{
case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS:
for (int i = 0; i < permissions.length; i++)
{
if(grantResults[i] == PackageManager.PERMISSION_GRANTED)
{
Log.i("RetroActivity", "Permission: " + permissions[i] + " was granted.");
}
else
{
Log.i("RetroActivity", "Permission: " + permissions[i] + " was not granted.");
}
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
break;
}
}
public boolean isAndroidTV() public boolean isAndroidTV()
{ {
Configuration config = getResources().getConfiguration(); Configuration config = getResources().getConfiguration();