diff --git a/src/Kp2aBusinessLogic/Io/BuiltInFileStorage.cs b/src/Kp2aBusinessLogic/Io/BuiltInFileStorage.cs index edb3477a..45a7e010 100644 --- a/src/Kp2aBusinessLogic/Io/BuiltInFileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/BuiltInFileStorage.cs @@ -3,18 +3,25 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Net; -using System.Net.Security; using System.Security; +using Android; +using Android.App; using Android.Content; +using Android.Content.PM; using Android.OS; -using Java.Security.Cert; +using Java.IO; using KeePassLib.Serialization; using KeePassLib.Utility; +using File = System.IO.File; +using FileNotFoundException = System.IO.FileNotFoundException; +using IOException = System.IO.IOException; namespace keepass2android.Io { - public class BuiltInFileStorage: IFileStorage + public class BuiltInFileStorage : IFileStorage, IPermissionRequestingFileStorage { + private const string PermissionGrantedKey = "PermissionGranted"; + public enum CertificateProblem :long { CertEXPIRED = 0x800B0101, @@ -112,7 +119,8 @@ namespace keepass2android.Io private void ConvertException(IOConnectionInfo ioc, WebException ex) { - if ((ex.Response is HttpWebResponse) && (((HttpWebResponse) ex.Response).StatusCode == HttpStatusCode.NotFound)) + var response = ex.Response as HttpWebResponse; + if ((response != null) && (response.StatusCode == HttpStatusCode.NotFound)) { throw new FileNotFoundException(ex.Message, ioc.Path, ex); } @@ -241,6 +249,26 @@ namespace keepass2android.Io public void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode, bool alwaysReturnSuccess) { + //check if we need to request the external-storage-permission at runtime + if (ioc.IsLocalFile()) + { + bool requiresPermission = !ioc.Path.StartsWith(activity.Activity.FilesDir.CanonicalPath); + + var extDirectory = activity.Activity.GetExternalFilesDir(null); + if ((extDirectory != null) && (ioc.Path.StartsWith(extDirectory.CanonicalPath))) + requiresPermission = false; + + if (requiresPermission && (Build.VERSION.SdkInt >= BuildVersionCodes.M)) + { + if (activity.Activity.CheckSelfPermission(Manifest.Permission.WriteExternalStorage) == + Permission.Denied) + { + activity.StartFileUsageProcess(ioc, requestCode, alwaysReturnSuccess); + return; + } + } + + } Intent intent = new Intent(); activity.IocToIntent(intent, ioc); activity.OnImmediateResult(requestCode, (int) FileStorageResults.FileUsagePrepared, intent); @@ -251,24 +279,42 @@ namespace keepass2android.Io //nothing to do, we're ready to go } - public void OnCreate(IFileStorageSetupActivity activity, Bundle savedInstanceState) + public void OnCreate(IFileStorageSetupActivity fileStorageSetupActivity, Bundle savedInstanceState) { - throw new NotImplementedException(); + ((Activity)fileStorageSetupActivity).RequestPermissions(new[] { Manifest.Permission.WriteExternalStorage }, 0); } public void OnResume(IFileStorageSetupActivity activity) { - throw new NotImplementedException(); + if (activity.State.ContainsKey(PermissionGrantedKey)) + { + if (activity.State.GetBoolean(PermissionGrantedKey)) + { + Intent data = new Intent(); + data.PutExtra(FileStorageSetupDefs.ExtraIsForSave, activity.IsForSave); + data.PutExtra(FileStorageSetupDefs.ExtraPath, IocToPath(activity.Ioc)); + ((Activity) activity).SetResult((Result) FileStorageResults.FileUsagePrepared, data); + ((Activity) activity).Finish(); + } + else + { + Intent data = new Intent(); + data.PutExtra(FileStorageSetupDefs.ExtraErrorMessage, "Permission denied. Please grant file access permission for this app."); + ((Activity)activity).SetResult(Result.Canceled, data); + ((Activity)activity).Finish(); + + } + } } public void OnStart(IFileStorageSetupActivity activity) { - throw new NotImplementedException(); + } public void OnActivityResult(IFileStorageSetupActivity activity, int requestCode, int resultCode, Intent data) { - throw new NotImplementedException(); + } public string GetDisplayName(IOConnectionInfo ioc) @@ -310,7 +356,7 @@ namespace keepass2android.Io { //test if we can open //http://www.doubleencore.com/2014/03/android-external-storage/#comment-1294469517 - using (var writer = new Java.IO.FileOutputStream(ioc.Path, true)) + using (var writer = new FileOutputStream(ioc.Path, true)) { writer.Close(); return false; //we can write @@ -358,5 +404,11 @@ namespace keepass2android.Io return false; } } + + public void OnRequestPermissionsResult(IFileStorageSetupActivity fileStorageSetupActivity, int requestCode, + string[] permissions, Permission[] grantResults) + { + fileStorageSetupActivity.State.PutBoolean(PermissionGrantedKey, grantResults[0] == Permission.Granted); + } } } \ No newline at end of file diff --git a/src/Kp2aBusinessLogic/Io/CachingFileStorage.cs b/src/Kp2aBusinessLogic/Io/CachingFileStorage.cs index 4a0ee35b..890751be 100644 --- a/src/Kp2aBusinessLogic/Io/CachingFileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/CachingFileStorage.cs @@ -5,6 +5,7 @@ using System.Net; using System.Security.Cryptography; using System.Text; using Android.Content; +using Android.Content.PM; using Android.OS; using KeePassLib.Cryptography; using KeePassLib.Serialization; @@ -59,7 +60,7 @@ namespace keepass2android.Io /// Implements the IFileStorage interface as a proxy: A base storage is used as a remote storage. Local files are used to cache the /// files on remote. /// - public class CachingFileStorage : IFileStorage, IOfflineSwitchable + public class CachingFileStorage : IFileStorage, IOfflineSwitchable, IPermissionRequestingFileStorage { protected readonly OfflineSwitchableFileStorage _cachedStorage; @@ -618,5 +619,11 @@ namespace keepass2android.Io get { return _cachedStorage.IsOffline; } set { _cachedStorage.IsOffline = value; } } + + public void OnRequestPermissionsResult(IFileStorageSetupActivity fileStorageSetupActivity, int requestCode, + string[] permissions, Permission[] grantResults) + { + _cachedStorage.OnRequestPermissionsResult(fileStorageSetupActivity, requestCode, permissions, grantResults); + } } } diff --git a/src/Kp2aBusinessLogic/Io/IFileStorage.cs b/src/Kp2aBusinessLogic/Io/IFileStorage.cs index a290acb2..1ffc6ece 100644 --- a/src/Kp2aBusinessLogic/Io/IFileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/IFileStorage.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using Android.Content; +using Android.Content.PM; using Android.OS; using KeePassLib.Serialization; @@ -22,7 +23,7 @@ namespace keepass2android.Io public static String ExtraProcessName = "EXTRA_PROCESS_NAME"; public static String ExtraAlwaysReturnSuccess = "EXTRA_ALWAYS_RETURN_SUCCESS"; - public static String ExtraPath = "PATH"; + public static String ExtraPath = "fileName"; //match KP2A PasswordActivity Ioc-Path Extra key public static String ExtraIsForSave = "IS_FOR_SAVE"; public static String ExtraErrorMessage = "EXTRA_ERROR_MESSAGE"; @@ -170,6 +171,11 @@ namespace keepass2android.Io bool IsReadOnly(IOConnectionInfo ioc); } + public interface IPermissionRequestingFileStorage + { + void OnRequestPermissionsResult(IFileStorageSetupActivity fileStorageSetupActivity, int requestCode, string[] permissions, Permission[] grantResults); + } + public interface IWriteTransaction: IDisposable { Stream OpenFile(); diff --git a/src/Kp2aBusinessLogic/Io/JavaFileStorage.cs b/src/Kp2aBusinessLogic/Io/JavaFileStorage.cs index 63e0855d..4ec59226 100644 --- a/src/Kp2aBusinessLogic/Io/JavaFileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/JavaFileStorage.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using Android.App; using Android.Content; +using Android.Content.PM; using Android.OS; using KeePassLib.Serialization; using KeePassLib.Utility; @@ -16,7 +17,7 @@ using FileNotFoundException = Java.IO.FileNotFoundException; namespace keepass2android.Io { #if !EXCLUDE_JAVAFILESTORAGE - public abstract class JavaFileStorage: IFileStorage + public abstract class JavaFileStorage: IFileStorage, IPermissionRequestingFileStorage { protected string Protocol { get { return _jfs.ProtocolId; } } @@ -356,6 +357,12 @@ namespace keepass2android.Io return ioc.Path; } + public void OnRequestPermissionsResult(IFileStorageSetupActivity fileStorageSetupActivity, int requestCode, + string[] permissions, Permission[] grantResults) + { + _jfs.OnRequestPermissionsResult(((IJavaFileStorageFileStorageSetupActivity) fileStorageSetupActivity), requestCode, + permissions, grantResults.Select(p => (int)p).ToArray()); + } } #endif } \ No newline at end of file diff --git a/src/Kp2aBusinessLogic/Io/OfflineSwitchableFileStorage.cs b/src/Kp2aBusinessLogic/Io/OfflineSwitchableFileStorage.cs index 8f492da7..70f9529b 100644 --- a/src/Kp2aBusinessLogic/Io/OfflineSwitchableFileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/OfflineSwitchableFileStorage.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using Android.Content; +using Android.Content.PM; using Android.OS; using KeePassLib.Serialization; @@ -16,7 +17,7 @@ namespace keepass2android.Io /// Encapsulates another IFileStorage. Allows to switch to offline mode by throwing /// an exception when trying to read or write a file. /// - public class OfflineSwitchableFileStorage : IFileStorage, IOfflineSwitchable + public class OfflineSwitchableFileStorage : IFileStorage, IOfflineSwitchable, IPermissionRequestingFileStorage { private readonly IFileStorage _baseStorage; public bool IsOffline { get; set; } @@ -179,6 +180,15 @@ namespace keepass2android.Io { return _baseStorage.IsReadOnly(ioc); } + + public void OnRequestPermissionsResult(IFileStorageSetupActivity fileStorageSetupActivity, int requestCode, + string[] permissions, Permission[] grantResults) + { + if (_baseStorage is IPermissionRequestingFileStorage) + { + ((IPermissionRequestingFileStorage)_baseStorage).OnRequestPermissionsResult(fileStorageSetupActivity, requestCode, permissions, grantResults); + } + } } public class OfflineModeException : Exception diff --git a/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj b/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj index 8cfad986..9a82467e 100644 --- a/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj +++ b/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj @@ -12,7 +12,8 @@ 512 Resources\Resource.Designer.cs Off - v5.0 + v6.0 + False true diff --git a/src/java/JavaFileStorage/app/app.iml b/src/java/JavaFileStorage/app/app.iml index 91b64a71..889b621b 100644 --- a/src/java/JavaFileStorage/app/app.iml +++ b/src/java/JavaFileStorage/app/app.iml @@ -85,7 +85,7 @@ - + @@ -104,8 +104,8 @@ - + diff --git a/src/java/JavaFileStorage/app/build.gradle b/src/java/JavaFileStorage/app/build.gradle index d5dd100f..b6578585 100644 --- a/src/java/JavaFileStorage/app/build.gradle +++ b/src/java/JavaFileStorage/app/build.gradle @@ -1,20 +1,20 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 21 - buildToolsVersion "21.1.2" - + compileSdkVersion 23 + buildToolsVersion '23.0.0' defaultConfig { minSdkVersion 14 - targetSdkVersion 21 + targetSdkVersion 23 } - buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt' } } + productFlavors { + } } dependencies { diff --git a/src/java/JavaFileStorage/app/build/outputs/aar/app-debug.aar b/src/java/JavaFileStorage/app/build/outputs/aar/app-debug.aar index 51287905..3ca10e5f 100644 Binary files a/src/java/JavaFileStorage/app/build/outputs/aar/app-debug.aar and b/src/java/JavaFileStorage/app/build/outputs/aar/app-debug.aar differ diff --git a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/GoogleDriveFileStorage.java b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/GoogleDriveFileStorage.java index b8f87a23..bb95c329 100644 --- a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/GoogleDriveFileStorage.java +++ b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/GoogleDriveFileStorage.java @@ -27,11 +27,14 @@ import com.google.api.services.drive.model.File; import com.google.api.services.drive.model.FileList; import com.google.api.services.drive.model.ParentReference; +import android.Manifest; import android.accounts.AccountManager; import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.os.AsyncTask; +import android.os.Build; import android.os.Bundle; import android.text.TextUtils; @@ -43,9 +46,9 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { static final int MAGIC_GDRIVE=2082334; static final int REQUEST_ACCOUNT_PICKER = MAGIC_GDRIVE+1; static final int REQUEST_AUTHORIZATION = MAGIC_GDRIVE+2; + private boolean mRequiresRuntimePermissions = false; + - - class FileSystemEntryData { String displayName; @@ -253,7 +256,7 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { public GoogleDriveFileStorage() { - logDebug("Creating GDrive FileStorage"); + logDebug("Creating GDrive FileStorage."); } @Override @@ -370,7 +373,7 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { GDrivePath parentGdrivePath = new GDrivePath(parentPath); body.setParents( - Arrays.asList(new ParentReference().setId(parentGdrivePath.getGDriveId()))); + Arrays.asList(new ParentReference().setId(parentGdrivePath.getGDriveId()))); try { File file = getDriveService(parentGdrivePath.getAccount()).files().insert(body).execute(); @@ -393,7 +396,7 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { GDrivePath parentGdrivePath = new GDrivePath(parentPath); body.setParents( - Arrays.asList(new ParentReference().setId(parentGdrivePath.getGDriveId()))); + Arrays.asList(new ParentReference().setId(parentGdrivePath.getGDriveId()))); try { File file = getDriveService(parentGdrivePath.getAccount()).files().insert(body).execute(); @@ -424,7 +427,7 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { throw new FileNotFoundException(parentPath + " is trashed!"); logDebug("listing files in "+parentId); Files.List request = driveService.files().list() - .setQ("trashed=false and '"+parentId+"' in parents"); + .setQ("trashed=false and '" + parentId + "' in parents"); do { try { @@ -505,7 +508,7 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { FileEntry res = convertToFileEntry( getFileForPath(gdrivePath, getDriveService(gdrivePath.getAccount())), filename); - logDebug("getFileEntry res"+res); + logDebug("getFileEntry res" + res); return res; } catch (Exception e) @@ -551,13 +554,13 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { { logDebug("getDriveService "+accountName); AccountData accountData = mAccountData.get(accountName); - logDebug("accountData "+accountData); + logDebug("accountData " + accountData); return accountData.drive; } @Override public void onActivityResult(final JavaFileStorage.FileStorageSetupActivity setupAct, int requestCode, int resultCode, Intent data) { - logDebug("ActivityResult: "+requestCode+"/"+resultCode); + logDebug("ActivityResult: " + requestCode + "/" + resultCode); switch (requestCode) { case REQUEST_ACCOUNT_PICKER: logDebug("ActivityResult: REQUEST_ACCOUNT_PICKER"); @@ -773,6 +776,38 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { } + @Override + public void onRequestPermissionsResult(FileStorageSetupActivity setupAct, int requestCode, String[] permissions, int[] grantResults) + { + logDebug("onRequestPermissionsResult"); + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) + { + logDebug("granted"); + initFileStorage(setupAct); + } + else + { + logDebug("denied"); + finishWithError(setupAct, new Exception("You must grant the requested permissions to continue.")); + } + } + + private void initFileStorage(FileStorageSetupActivity setupAct) { + Activity activity = (Activity)setupAct; + + if (PROCESS_NAME_SELECTFILE.equals(setupAct.getProcessName())) + { + GoogleAccountCredential credential = createCredential(activity.getApplicationContext()); + + logDebug("starting REQUEST_ACCOUNT_PICKER"); + activity.startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER); + } + + if (PROCESS_NAME_FILE_USAGE_SETUP.equals(setupAct.getProcessName())) + { + initializeAccountOrPath(setupAct, setupAct.getPath()); + } + } @Override public void onResume(JavaFileStorage.FileStorageSetupActivity setupAct) { @@ -781,22 +816,13 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { @Override public void onStart(final JavaFileStorage.FileStorageSetupActivity setupAct) { - - logDebug("onStart"); - Activity activity = (Activity)setupAct; - - if (PROCESS_NAME_SELECTFILE.equals(setupAct.getProcessName())) + logDebug("onStart "+mRequiresRuntimePermissions); + if (!mRequiresRuntimePermissions) { - GoogleAccountCredential credential = createCredential(activity.getApplicationContext()); - - logDebug("starting REQUEST_ACCOUNT_PICKER"); - activity.startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER); + initFileStorage(setupAct); } - if (PROCESS_NAME_FILE_USAGE_SETUP.equals(setupAct.getProcessName())) - { - initializeAccountOrPath(setupAct, setupAct.getPath()); - } + } private GoogleAccountCredential createCredential(Context appContext) { @@ -816,6 +842,21 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { public void onCreate(FileStorageSetupActivity activity, Bundle savedInstanceState) { + logDebug("onCreate"); + mRequiresRuntimePermissions = false; + if (Build.VERSION.SDK_INT >= 23) + { + Activity act = (Activity)activity; + int permissionRes = act.checkSelfPermission(Manifest.permission.GET_ACCOUNTS); + logDebug("permissionRes="+permissionRes); + if (permissionRes == PackageManager.PERMISSION_DENIED) + { + logDebug("requestPermissions"); + mRequiresRuntimePermissions = true; + act.requestPermissions(new String[] {Manifest.permission.GET_ACCOUNTS}, 0); + } + } + } diff --git a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/JavaFileStorage.java b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/JavaFileStorage.java index 0bf332fc..0dca7e9d 100644 --- a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/JavaFileStorage.java +++ b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/JavaFileStorage.java @@ -18,7 +18,7 @@ public interface JavaFileStorage { public static final String EXTRA_PATH = "fileName"; //match KP2A PasswordActivity Ioc-Path Extra key public static final String EXTRA_IS_FOR_SAVE = "IS_FOR_SAVE"; public static final String EXTRA_ERROR_MESSAGE = "EXTRA_ERROR_MESSAGE"; - public static final String EXTRA_ALWAYS_RETURN_SUCCESS = "EXTRA_ALWAYS_RETURN_SUCCESS";; + public static final String EXTRA_ALWAYS_RETURN_SUCCESS = "EXTRA_ALWAYS_RETURN_SUCCESS"; public interface FileStorageSetupInitiatorActivity @@ -155,5 +155,6 @@ public class FileEntry { public void onResume(FileStorageSetupActivity activity); public void onStart(FileStorageSetupActivity activity); public void onActivityResult(FileStorageSetupActivity activity, int requestCode, int resultCode, Intent data); + public void onRequestPermissionsResult(FileStorageSetupActivity activity, int requestCode, String[] permissions, int[] grantResults); } \ No newline at end of file diff --git a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/JavaFileStorageBase.java b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/JavaFileStorageBase.java index b2a8f999..f598fd2b 100644 --- a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/JavaFileStorageBase.java +++ b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/JavaFileStorageBase.java @@ -147,5 +147,10 @@ public abstract class JavaFileStorageBase implements JavaFileStorage{ } + public void onRequestPermissionsResult(FileStorageSetupActivity activity, int requestCode, String[] permissions, int[] grantResults) + { + + } + } diff --git a/src/keepass2android/CreateDatabaseActivity.cs b/src/keepass2android/CreateDatabaseActivity.cs index 983d6f4c..191da39d 100644 --- a/src/keepass2android/CreateDatabaseActivity.cs +++ b/src/keepass2android/CreateDatabaseActivity.cs @@ -287,13 +287,20 @@ namespace keepass2android private void SetDefaultIoc() { - var sdDir = SdDir; - string filename = sdDir + "keepass.kdbx"; + File directory = GetExternalFilesDir(null); + if (directory == null) + directory = FilesDir; + + string strDir = directory.CanonicalPath; + if (!strDir.EndsWith(File.Separator)) + strDir += File.Separator; + + string filename = strDir + "keepass.kdbx"; filename = ConvertFilenameToIocPath(filename); int count = 2; while (new File(filename).Exists()) { - filename = ConvertFilenameToIocPath(sdDir + "keepass" + count + ".kdbx"); + filename = ConvertFilenameToIocPath(strDir + "keepass" + count + ".kdbx"); count++; } diff --git a/src/keepass2android/PasswordActivity.cs b/src/keepass2android/PasswordActivity.cs index e72b4f40..09707b2f 100644 --- a/src/keepass2android/PasswordActivity.cs +++ b/src/keepass2android/PasswordActivity.cs @@ -71,7 +71,8 @@ namespace keepass2android LaunchMode = LaunchMode.SingleInstance, WindowSoftInputMode = SoftInput.AdjustResize, Theme = "@style/MyTheme_Blue")] /*caution: also contained in AndroidManifest.xml*/ - public class PasswordActivity : LockingActivity, IFingerprintAuthCallback + [IntentFilter(new[] { "kp2a.action.PasswordActivity" }, Categories = new[] { Intent.CategoryDefault })] + public class PasswordActivity : LockingActivity, IFingerprintAuthCallback { enum KeyProviders diff --git a/src/keepass2android/Properties/AndroidManifest_debug.xml b/src/keepass2android/Properties/AndroidManifest_debug.xml index eb16b722..860c126f 100644 --- a/src/keepass2android/Properties/AndroidManifest_debug.xml +++ b/src/keepass2android/Properties/AndroidManifest_debug.xml @@ -1,6 +1,6 @@  - + diff --git a/src/keepass2android/Properties/AndroidManifest_net.xml b/src/keepass2android/Properties/AndroidManifest_net.xml index e3bafa41..881671cb 100644 --- a/src/keepass2android/Properties/AndroidManifest_net.xml +++ b/src/keepass2android/Properties/AndroidManifest_net.xml @@ -4,7 +4,7 @@ android:versionName="1.0.0 preview 2" package="keepass2android.keepass2android" android:installLocation="auto"> - + diff --git a/src/keepass2android/Properties/AndroidManifest_nonet.xml b/src/keepass2android/Properties/AndroidManifest_nonet.xml index 1508c61a..951fd68e 100644 --- a/src/keepass2android/Properties/AndroidManifest_nonet.xml +++ b/src/keepass2android/Properties/AndroidManifest_nonet.xml @@ -4,7 +4,7 @@ android:versionName="0.9.8b" package="keepass2android.keepass2android_nonet" android:installLocation="auto"> - + diff --git a/src/keepass2android/Resources/values-iw/strings.xml b/src/keepass2android/Resources/values-iw/strings.xml deleted file mode 100644 index 7ad103b9..00000000 --- a/src/keepass2android/Resources/values-iw/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/keepass2android/Resources/values/strings.xml b/src/keepass2android/Resources/values/strings.xml index b6ab7735..961e3a9c 100644 --- a/src/keepass2android/Resources/values/strings.xml +++ b/src/keepass2android/Resources/values/strings.xml @@ -594,11 +594,13 @@ - Version 1.0.0 - preview 1\n + Version 1.0.0 - preview 2\n + * Fingerprint Unlock (requires Android 6.0 or later)\n * Added "work offline" mode\n * Allow to copy entries\n * Auto-complete mode for field names\n * Allow to remove items from recent files list\n + * Request permissions at runtime in Android 6.0\n * more to come...\n diff --git a/src/keepass2android/fileselect/FileStorageSetupActivity.cs b/src/keepass2android/fileselect/FileStorageSetupActivity.cs index ce686e87..25ae1667 100644 --- a/src/keepass2android/fileselect/FileStorageSetupActivity.cs +++ b/src/keepass2android/fileselect/FileStorageSetupActivity.cs @@ -87,7 +87,18 @@ namespace keepass2android.fileselect App.Kp2a.GetFileStorage(Ioc).OnActivityResult(this, requestCode, (int) resultCode, data); } - protected override void OnSaveInstanceState(Bundle outState) + public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults) + { + base.OnRequestPermissionsResult(requestCode, permissions, grantResults); + var fileStorage = App.Kp2a.GetFileStorage(Ioc); + if (fileStorage is IPermissionRequestingFileStorage) + { + ((IPermissionRequestingFileStorage)fileStorage).OnRequestPermissionsResult(this, requestCode, permissions, grantResults); + } + + } + + protected override void OnSaveInstanceState(Bundle outState) { base.OnSaveInstanceState(outState); diff --git a/src/keepass2android/keepass2android.csproj b/src/keepass2android/keepass2android.csproj index a482aa3a..d96039f0 100644 --- a/src/keepass2android/keepass2android.csproj +++ b/src/keepass2android/keepass2android.csproj @@ -86,17 +86,17 @@ + + ..\packages\Xamarin.Android.Support.v7.MediaRouter.21.0.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.MediaRouter.dll + - ..\packages\Xamarin.Android.Support.v4.23.1.1.0\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll + ..\packages\Xamarin.Android.Support.v4.22.2.1.0\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll - ..\packages\Xamarin.Android.Support.v7.AppCompat.23.1.1.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.AppCompat.dll - - - ..\packages\Xamarin.Android.Support.v7.RecyclerView.23.1.1.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.RecyclerView.dll + ..\packages\Xamarin.Android.Support.v7.AppCompat.22.2.1.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.AppCompat.dll - ..\packages\Xamarin.Android.Support.Design.23.1.1.0\lib\MonoAndroid403\Xamarin.Android.Support.Design.dll + ..\packages\Xamarin.Android.Support.Design.22.2.1.0\lib\MonoAndroid403\Xamarin.Android.Support.Design.dll ..\packages\Xamarin.GooglePlayServices.Base.27.0.0.0\lib\MonoAndroid41\Xamarin.GooglePlayServices.Base.dll @@ -671,7 +671,6 @@ - @@ -729,7 +728,6 @@ - @@ -847,6 +845,12 @@ Designer + + + 22.2.0.0 + False + + @@ -1643,12 +1647,6 @@ - - - False - 23.0.1.3 - - diff --git a/src/keepass2android/packages.config b/src/keepass2android/packages.config index e35326ad..15f24723 100644 --- a/src/keepass2android/packages.config +++ b/src/keepass2android/packages.config @@ -1,9 +1,9 @@  - - - - + + + +