From 181cdc4c2ecc2a064d0e7462e1eed34a35a9ded5 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Wed, 13 Dec 2017 19:00:58 +0100 Subject: [PATCH] Request permissions at runtime if needed --- .../main/java/me/impy/aegis/MainActivity.java | 126 ++++++++++++------ .../impy/aegis/helpers/PermissionHelper.java | 39 ++++++ 2 files changed, 127 insertions(+), 38 deletions(-) create mode 100644 app/src/main/java/me/impy/aegis/helpers/PermissionHelper.java diff --git a/app/src/main/java/me/impy/aegis/MainActivity.java b/app/src/main/java/me/impy/aegis/MainActivity.java index 7e7e383b..3313eb26 100644 --- a/app/src/main/java/me/impy/aegis/MainActivity.java +++ b/app/src/main/java/me/impy/aegis/MainActivity.java @@ -1,5 +1,6 @@ package me.impy.aegis; +import android.Manifest; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; @@ -37,11 +38,13 @@ import java.util.List; import me.impy.aegis.crypto.MasterKey; import me.impy.aegis.db.DatabaseEntry; import me.impy.aegis.db.DatabaseManager; +import me.impy.aegis.helpers.PermissionHelper; import me.impy.aegis.importers.DatabaseImporter; import me.impy.aegis.helpers.SimpleItemTouchHelperCallback; import me.impy.aegis.util.ByteInputStream; public class MainActivity extends AppCompatActivity implements KeyProfileAdapter.Listener { + // activity request codes private static final int CODE_GET_KEYINFO = 0; private static final int CODE_ADD_KEYINFO = 1; private static final int CODE_DO_INTRO = 2; @@ -49,6 +52,11 @@ public class MainActivity extends AppCompatActivity implements KeyProfileAdapter private static final int CODE_IMPORT = 4; private static final int CODE_PREFERENCES = 5; + // permission request codes + private static final int CODE_PERM_EXPORT = 0; + private static final int CODE_PERM_IMPORT = 1; + private static final int CODE_PERM_CAMERA = 2; + private KeyProfileAdapter _keyProfileAdapter; private DatabaseManager _db; @@ -103,8 +111,7 @@ public class MainActivity extends AppCompatActivity implements KeyProfileAdapter FloatingActionButton fab = findViewById(R.id.fab); fab.setEnabled(true); fab.setOnClickListener(view -> { - Intent scannerActivity = new Intent(getApplicationContext(), ScannerActivity.class); - startActivityForResult(scannerActivity, CODE_GET_KEYINFO); + onGetKeyInfo(); }); RecyclerView rvKeyProfiles = findViewById(R.id.rvKeyProfiles); @@ -146,6 +153,26 @@ public class MainActivity extends AppCompatActivity implements KeyProfileAdapter } } + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + if (!PermissionHelper.checkResults(grantResults)) { + Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show(); + return; + } + + switch (requestCode) { + case CODE_PERM_EXPORT: + onExport(); + break; + case CODE_PERM_IMPORT: + onImport(); + break; + case CODE_PERM_CAMERA: + onGetKeyInfo(); + break; + } + } + private void onPreferencesResult(int resultCode, Intent data) { // refresh the entire key profile list if needed if (data.getBooleanExtra("needsRefresh", false)) { @@ -156,43 +183,57 @@ public class MainActivity extends AppCompatActivity implements KeyProfileAdapter int action = data.getIntExtra("action", -1); switch (action) { case PreferencesActivity.ACTION_EXPORT: - // TODO: create a custom layout to show a message AND a checkbox - final boolean[] checked = {true}; - AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this) - .setTitle("Export the database") - .setPositiveButton(android.R.string.ok, (dialog, which) -> { - String filename; - try { - filename = _db.export(checked[0]); - } catch (Exception e) { - e.printStackTrace(); - Toast.makeText(this, "An error occurred while trying to export the database", Toast.LENGTH_SHORT).show(); - return; - } - - // make sure the new file is visible - MediaScannerConnection.scanFile(this, new String[]{filename}, null, null); - - Toast.makeText(this, "The database has been exported to: " + filename, Toast.LENGTH_SHORT).show(); - }) - .setNegativeButton(android.R.string.cancel, null); - if (_db.getFile().isEncrypted()) { - final String[] items = {"Keep the database encrypted"}; - final boolean[] checkedItems = {true}; - builder.setMultiChoiceItems(items, checkedItems, new DialogInterface.OnMultiChoiceClickListener() { - @Override - public void onClick(DialogInterface dialog, int index, boolean isChecked) { - checked[0] = isChecked; - } - }); - } else { - builder.setMessage("This action will export the database out of Android's private storage."); - } - builder.show(); + onExport(); break; } } + private void onExport() { + if (!PermissionHelper.request(this, CODE_PERM_EXPORT, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + return; + } + + // TODO: create a custom layout to show a message AND a checkbox + final boolean[] checked = {true}; + AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this) + .setTitle("Export the database") + .setPositiveButton(android.R.string.ok, (dialog, which) -> { + String filename; + try { + filename = _db.export(checked[0]); + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(this, "An error occurred while trying to export the database", Toast.LENGTH_SHORT).show(); + return; + } + + // make sure the new file is visible + MediaScannerConnection.scanFile(this, new String[]{filename}, null, null); + + Toast.makeText(this, "The database has been exported to: " + filename, Toast.LENGTH_SHORT).show(); + }) + .setNegativeButton(android.R.string.cancel, null); + if (_db.getFile().isEncrypted()) { + final String[] items = {"Keep the database encrypted"}; + final boolean[] checkedItems = {true}; + builder.setMultiChoiceItems(items, checkedItems, new DialogInterface.OnMultiChoiceClickListener() { + @Override + public void onClick(DialogInterface dialog, int index, boolean isChecked) { + checked[0] = isChecked; + } + }); + } else { + builder.setMessage("This action will export the database out of Android's private storage."); + } + builder.show(); + } + + private void onImport() { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType("*/*"); + startActivityForResult(intent, CODE_IMPORT); + } + private void onImportResult(int resultCode, Intent data) { if (resultCode != RESULT_OK) { return; @@ -251,6 +292,15 @@ public class MainActivity extends AppCompatActivity implements KeyProfileAdapter saveDatabase(); } + private void onGetKeyInfo() { + if (!PermissionHelper.request(this, CODE_PERM_CAMERA, Manifest.permission.CAMERA)) { + return; + } + + Intent scannerActivity = new Intent(getApplicationContext(), ScannerActivity.class); + startActivityForResult(scannerActivity, CODE_GET_KEYINFO); + } + private void onGetKeyInfoResult(int resultCode, Intent data) { if (resultCode == RESULT_OK) { KeyProfile keyProfile = (KeyProfile)data.getSerializableExtra("KeyProfile"); @@ -420,9 +470,9 @@ public class MainActivity extends AppCompatActivity implements KeyProfileAdapter startActivityForResult(preferencesActivity, CODE_PREFERENCES); return true; case R.id.action_import: - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.setType("*/*"); - startActivityForResult(intent, CODE_IMPORT); + if (PermissionHelper.request(this, CODE_PERM_IMPORT, Manifest.permission.CAMERA)) { + onImport(); + } return true; case R.id.action_lock: // TODO: properly close the database diff --git a/app/src/main/java/me/impy/aegis/helpers/PermissionHelper.java b/app/src/main/java/me/impy/aegis/helpers/PermissionHelper.java new file mode 100644 index 00000000..ddc32f54 --- /dev/null +++ b/app/src/main/java/me/impy/aegis/helpers/PermissionHelper.java @@ -0,0 +1,39 @@ +package me.impy.aegis.helpers; + +import android.app.Activity; +import android.content.pm.PackageManager; +import android.support.v4.app.ActivityCompat; + +import java.util.ArrayList; +import java.util.List; + +public class PermissionHelper { + private PermissionHelper() { + + } + + public static boolean request(Activity activity, int requestCode, String... perms) { + List deniedPerms = new ArrayList<>(); + for (String permission : perms) { + if (ActivityCompat.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_DENIED) { + deniedPerms.add(permission); + } + } + + int size = deniedPerms.size(); + if (size > 0) { + String[] array = new String[size]; + ActivityCompat.requestPermissions(activity, deniedPerms.toArray(array), requestCode); + } + return size == 0; + } + + public static boolean checkResults(int[] grantResults) { + for (int result : grantResults) { + if (result != PackageManager.PERMISSION_GRANTED) { + return false; + } + } + return true; + } +}