diff --git a/app/build.gradle b/app/build.gradle
index d2f5b7e49..4a1848c55 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -62,6 +62,7 @@ android {
def supportVersion = "25.4.0"
def spongycastleVersion = "1.58.0.0"
+def permissionDispatcherVersion = "3.1.0"
dependencies {
androidTestCompile "junit:junit:4.12"
@@ -72,7 +73,14 @@ dependencies {
compile "com.android.support:cardview-v7:$supportVersion"
compile "com.madgag.spongycastle:core:$spongycastleVersion"
compile "com.madgag.spongycastle:prov:$spongycastleVersion"
+ // Time
compile "joda-time:joda-time:2.9.9"
compile "org.sufficientlysecure:html-textview:3.5"
compile "com.nononsenseapps:filepicker:4.1.0"
+ // Permissions
+ compile ("com.github.hotchemi:permissionsdispatcher:$permissionDispatcherVersion") {
+ // if you don't use android.app.Fragment you can exclude support for them
+ exclude module: "support-v13"
+ }
+ annotationProcessor "com.github.hotchemi:permissionsdispatcher-processor:$permissionDispatcherVersion"
}
diff --git a/app/src/main/java/com/keepassdroid/fileselect/FileSelectActivity.java b/app/src/main/java/com/keepassdroid/fileselect/FileSelectActivity.java
index e675eeefd..8a4e0eb69 100644
--- a/app/src/main/java/com/keepassdroid/fileselect/FileSelectActivity.java
+++ b/app/src/main/java/com/keepassdroid/fileselect/FileSelectActivity.java
@@ -22,15 +22,14 @@ package com.keepassdroid.fileselect;
import android.Manifest;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.ContextCompat;
+import android.support.v7.app.AlertDialog;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
@@ -41,19 +40,19 @@ import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
-import com.keepassdroid.fragments.AssignMasterKeyDialogFragment;
-import com.keepassdroid.fragments.CreateFileDialogFragment;
import com.keepassdroid.activities.GroupActivity;
-import com.keepassdroid.password.PasswordActivity;
-import com.keepassdroid.tasks.ProgressTask;
import com.keepassdroid.app.App;
import com.keepassdroid.compat.ContentResolverCompat;
import com.keepassdroid.compat.StorageAF;
import com.keepassdroid.database.edit.CreateDB;
import com.keepassdroid.database.edit.FileOnFinish;
import com.keepassdroid.database.exception.ContentFileNotFoundException;
+import com.keepassdroid.fragments.AssignMasterKeyDialogFragment;
+import com.keepassdroid.fragments.CreateFileDialogFragment;
import com.keepassdroid.intents.Intents;
+import com.keepassdroid.password.PasswordActivity;
import com.keepassdroid.stylish.StylishActivity;
+import com.keepassdroid.tasks.ProgressTask;
import com.keepassdroid.utils.EmptyUtils;
import com.keepassdroid.utils.Interaction;
import com.keepassdroid.utils.MenuUtil;
@@ -68,6 +67,14 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URLDecoder;
+import permissions.dispatcher.NeedsPermission;
+import permissions.dispatcher.OnNeverAskAgain;
+import permissions.dispatcher.OnPermissionDenied;
+import permissions.dispatcher.OnShowRationale;
+import permissions.dispatcher.PermissionRequest;
+import permissions.dispatcher.RuntimePermissions;
+
+@RuntimePermissions
public class FileSelectActivity extends StylishActivity implements
CreateFileDialogFragment.DefinePathDialogListener ,
AssignMasterKeyDialogFragment.AssignPasswordDialogListener,
@@ -77,7 +84,6 @@ public class FileSelectActivity extends StylishActivity implements
private static final String TAG = "FileSelectActivity";
- private static final int MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE = 111;
private RecyclerView mListFiles;
private FileSelectAdapter mAdapter;
private View fileListTitle;
@@ -501,59 +507,37 @@ public class FileSelectActivity extends StylishActivity implements
mAdapter.notifyDataSetChanged();
}
- private void checkStoragePermission() {
- // Here, thisActivity is the current activity
- if (ContextCompat.checkSelfPermission(FileSelectActivity.this,
- Manifest.permission.WRITE_EXTERNAL_STORAGE)
- != PackageManager.PERMISSION_GRANTED) {
+ @NeedsPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ void checkStoragePermission() {}
- // Should we show an explanation?
- //if (ActivityCompat.shouldShowRequestPermissionRationale(FileSelectActivity.this,
- // Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
+ @OnShowRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ void showRationaleForExternalStorage(final PermissionRequest request) {
+ new AlertDialog.Builder(this)
+ .setMessage(R.string.permission_external_storage_rationale)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ request.proceed();
+ }
+ })
+ .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ request.cancel();
+ }
+ })
+ .show();
+ }
- // Show an explanation to the user *asynchronously* -- don't block
- // this thread waiting for the user's response! After the user
- // sees the explanation, try again to request the permission.
+ @OnPermissionDenied(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ void showDeniedForExternalStorage() {
+ Toast.makeText(this, R.string.permission_external_storage_denied, Toast.LENGTH_SHORT).show();
+ }
- //} else {
-
- // No explanation needed, we can request the permission.
-
- ActivityCompat.requestPermissions(FileSelectActivity.this,
- new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
- MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE);
-
- // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
- // app-defined int constant. The callback method gets the
- // result of the request.
- //}
- }
- }
-
- @Override
- public void onRequestPermissionsResult(int requestCode,
- String permissions[], int[] grantResults) {
- switch (requestCode) {
- case MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE: {
- // If request is cancelled, the result arrays are empty.
- if (grantResults.length > 0
- && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
-
- // permission was granted, yay! Do the
- // contacts-related task you need to do.
-
- } else {
-
- // permission denied, boo! Disable the
- // functionality that depends on this permission.
- }
- return;
- }
-
- // other 'case' lines to check for other
- // permissions this app might request
- }
- }
+ @OnNeverAskAgain(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ void showNeverAskForExternalStorage() {
+ Toast.makeText(this, R.string.permission_external_storage_neverask, Toast.LENGTH_SHORT).show();
+ }
@Override
public boolean onCreateOptionsMenu(Menu menu) {
diff --git a/app/src/main/java/com/keepassdroid/password/PasswordActivity.java b/app/src/main/java/com/keepassdroid/password/PasswordActivity.java
index 0a38451a6..7862c679b 100644
--- a/app/src/main/java/com/keepassdroid/password/PasswordActivity.java
+++ b/app/src/main/java/com/keepassdroid/password/PasswordActivity.java
@@ -19,6 +19,7 @@
*/
package com.keepassdroid.password;
+import android.Manifest;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
@@ -32,6 +33,7 @@ import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.annotation.RequiresApi;
import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;
+import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar;
import android.text.Editable;
import android.text.TextWatcher;
@@ -76,6 +78,14 @@ import static com.keepassdroid.fingerprint.FingerPrintHelper.Mode.NOT_CONFIGURED
import static com.keepassdroid.fingerprint.FingerPrintHelper.Mode.OPEN_MODE;
import static com.keepassdroid.fingerprint.FingerPrintHelper.Mode.STORE_MODE;
+import permissions.dispatcher.NeedsPermission;
+import permissions.dispatcher.OnNeverAskAgain;
+import permissions.dispatcher.OnPermissionDenied;
+import permissions.dispatcher.OnShowRationale;
+import permissions.dispatcher.PermissionRequest;
+import permissions.dispatcher.RuntimePermissions;
+
+@RuntimePermissions
public class PasswordActivity extends LockingActivity
implements FingerPrintHelper.FingerPrintCallback, UriIntentInitTaskCallback {
@@ -261,6 +271,9 @@ public class PasswordActivity extends LockingActivity
// For check shutdown
super.onResume();
+ // Check the storage permission
+ checkStoragePermission();
+
new UriIntentInitTask(this, mRememberKeyfile)
.execute(getIntent());
}
@@ -843,4 +856,36 @@ public class PasswordActivity extends LockingActivity
}
}
}
+
+ @NeedsPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ void checkStoragePermission() {}
+
+ @OnShowRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ void showRationaleForExternalStorage(final PermissionRequest request) {
+ new AlertDialog.Builder(this)
+ .setMessage(R.string.permission_external_storage_rationale)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ request.proceed();
+ }
+ })
+ .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ request.cancel();
+ }
+ })
+ .show();
+ }
+
+ @OnPermissionDenied(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ void showDeniedForExternalStorage() {
+ Toast.makeText(this, R.string.permission_external_storage_denied, Toast.LENGTH_SHORT).show();
+ }
+
+ @OnNeverAskAgain(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ void showNeverAskForExternalStorage() {
+ Toast.makeText(this, R.string.permission_external_storage_neverask, Toast.LENGTH_SHORT).show();
+ }
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 5ea88ee3e..a05193c51 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -253,6 +253,9 @@
View the full file path
Use Recycle Bin
Move a group or entry to the Recycle Bin before deleting
+ Application need external storage permission
+ Permission_external_storage_denied
+ Permission_external_storage_neverask
- 5 seconds