display reason why file is read only when first opening a database

This commit is contained in:
Philipp Crocoll 2016-01-13 05:13:02 +01:00
parent cd5fc13939
commit 64e265b2be
10 changed files with 86 additions and 13 deletions

View File

@ -206,12 +206,15 @@ namespace keepass2android.Io
return _ctx.ContentResolver.PersistedUriPermissions.Any(p => p.Uri.ToString().Equals(ioc.Path));
}
public bool IsReadOnly(IOConnectionInfo ioc)
public bool IsReadOnly(IOConnectionInfo ioc, OptionalOut<UiStringKey> reason = null)
{
//on pre-Kitkat devices, we can't write content:// files
if (!IsKitKatOrLater)
{
Kp2aLog.Log("File is read-only because we're not on KitKat or later.");
if (reason != null)
reason.Result = UiStringKey.ReadOnlyReason_PreKitKat;
return true;
}
@ -226,7 +229,12 @@ namespace keepass2android.Io
{
int flags = cursor.GetInt(cursor.GetColumnIndex(DocumentsContract.Document.ColumnFlags));
Kp2aLog.Log("File flags: " + flags);
return (flags & (long) DocumentContractFlags.SupportsWrite) == 0;
if ((flags & (long) DocumentContractFlags.SupportsWrite) == 0)
{
if (reason != null)
reason.Result = UiStringKey.ReadOnlyReason_ReadOnlyFlag;
return true;
}
}
}
finally

View File

@ -370,14 +370,24 @@ namespace keepass2android.Io
}
public bool IsReadOnly(IOConnectionInfo ioc)
public bool IsReadOnly(IOConnectionInfo ioc, OptionalOut<UiStringKey> reason = null)
{
if (ioc.IsLocalFile())
{
if (IsLocalFileFlaggedReadOnly(ioc))
{
if (reason != null)
reason.Result = UiStringKey.ReadOnlyReason_ReadOnlyFlag;
return true;
}
if (IsReadOnlyBecauseKitkatRestrictions(ioc))
{
if (reason != null)
reason.Result = UiStringKey.ReadOnlyReason_ReadOnlyKitKat;
return true;
}
return false;
}

View File

@ -556,11 +556,11 @@ namespace keepass2android.Io
return _cachedStorage.IsPermanentLocation(ioc);
}
public bool IsReadOnly(IOConnectionInfo ioc)
public bool IsReadOnly(IOConnectionInfo ioc, OptionalOut<UiStringKey> reason = null)
{
//even though the cache can always be written, the changes made in the cache could not be transferred to the cached file
//so we better treat the cache as read-only as well.
return _cachedStorage.IsReadOnly(ioc);
return _cachedStorage.IsReadOnly(ioc, reason);
}
private void StoreFilePath(IOConnectionInfo folderPath, string filename, IOConnectionInfo res)

View File

@ -16,6 +16,11 @@ namespace keepass2android.Io
FileUsagePrepared = FileChooserPrepared + 1
}
public class OptionalOut<T>
{
public T Result { get; set; }
}
public static class FileStorageSetupDefs
{
public static String ProcessNameSelectfile = "SELECT_FILE";
@ -165,10 +170,14 @@ namespace keepass2android.Io
/// Does not require to exist forever!
bool IsPermanentLocation(IOConnectionInfo ioc);
/// <summary>
/// Should return true if the file cannot be written.
/// </summary>
bool IsReadOnly(IOConnectionInfo ioc);
bool IsReadOnly(IOConnectionInfo ioc, OptionalOut<UiStringKey> reason = null );
}
public interface IPermissionRequestingFileStorage

View File

@ -289,7 +289,7 @@ namespace keepass2android.Io
return true;
}
public bool IsReadOnly(IOConnectionInfo ioc)
public bool IsReadOnly(IOConnectionInfo ioc, OptionalOut<UiStringKey> reason = null)
{
return false; //TODO implement. note, however, that we MAY return false even if it's read-only
}

View File

@ -176,9 +176,9 @@ namespace keepass2android.Io
return _baseStorage.IsPermanentLocation(ioc);
}
public bool IsReadOnly(IOConnectionInfo ioc)
public bool IsReadOnly(IOConnectionInfo ioc, OptionalOut<UiStringKey> reason = null)
{
return _baseStorage.IsReadOnly(ioc);
return _baseStorage.IsReadOnly(ioc, reason);
}
public void OnRequestPermissionsResult(IFileStorageSetupActivity fileStorageSetupActivity, int requestCode,

View File

@ -81,6 +81,9 @@ namespace keepass2android
TemplateTitle_Membership,
TemplateGroupName,
AskAddTemplatesTitle,
AskAddTemplatesMessage
AskAddTemplatesMessage,
ReadOnlyReason_PreKitKat,
ReadOnlyReason_ReadOnlyFlag,
ReadOnlyReason_ReadOnlyKitKat
}
}

View File

@ -153,12 +153,24 @@ namespace keepass2android
public static string GetFingerprintPrefKey(IOConnectionInfo ioc)
{
SHA256Managed sha256 = new SHA256Managed();
string iocAsHexString = MemUtil.ByteArrayToHexString(sha256.ComputeHash(Encoding.Unicode.GetBytes(ioc.Path.ToCharArray())));
var iocAsHexString = IocAsHexString(ioc);
return "kp2a_ioc_" + iocAsHexString;
}
public string IocAsHexString()
{
return IocAsHexString(Ioc);
}
private static string IocAsHexString(IOConnectionInfo ioc)
{
SHA256Managed sha256 = new SHA256Managed();
string iocAsHexString =
MemUtil.ByteArrayToHexString(sha256.ComputeHash(Encoding.Unicode.GetBytes(ioc.Path.ToCharArray())));
return iocAsHexString;
}
public static string GetFingerprintModePrefKey(IOConnectionInfo ioc)
{
return GetFingerprintPrefKey(ioc) + "_mode";

View File

@ -35,6 +35,7 @@ using Android.Preferences;
using Android.Runtime;
using Android.Support.V4.View;
using Android.Support.V7.App;
using keepass2android.Io;
using KeePassLib.Security;
using AlertDialog = Android.App.AlertDialog;
using Object = Java.Lang.Object;
@ -259,6 +260,29 @@ namespace keepass2android
FragmentManager.FindFragmentById<GroupListFragment>(Resource.Id.list_fragment).ListAdapter = new PwGroupListAdapter(this, Group);
Log.Warn(Tag, "Finished creating group");
var ioc = App.Kp2a.GetDb().Ioc;
OptionalOut<UiStringKey> reason = new OptionalOut<UiStringKey>();
if (App.Kp2a.GetFileStorage(ioc).IsReadOnly(ioc, reason))
{
bool hasShownReadOnlyReason =
PreferenceManager.GetDefaultSharedPreferences(this)
.GetBoolean(App.Kp2a.GetDb().IocAsHexString() + "_readonlyreason", false);
if (!hasShownReadOnlyReason)
{
var b = new AlertDialog.Builder(this);
b.SetTitle(Resource.String.FileReadOnlyTitle);
b.SetMessage(GetString(Resource.String.FileReadOnlyMessagePre) + " " + App.Kp2a.GetResourceString(reason.Result));
b.SetPositiveButton(Android.Resource.String.Ok,
(sender, args) =>
{
PreferenceManager.GetDefaultSharedPreferences(this).
Edit().PutBoolean(App.Kp2a.GetDb().IocAsHexString() + "_readonlyreason", true).Commit();
});
b.Show();
}
}
}
private void StartAddEntry()

View File

@ -573,6 +573,13 @@
<string name="ClickOkToSelectLocation">Click OK to select a location where the file should be copied.</string>
<string name="CancelReadOnly">Cancel, open read-only.</string>
<string name="FileReadOnlyTitle">Database is read-only</string>
<string name="FileReadOnlyMessagePre">Keepass2Android has opened the current database in read-only mode.</string>
<string name="ReadOnlyReason_PreKitKat">It seems like you opened the file from an external app. This way does not support writing. If you want to make changes to the database, please close the database and select Change database. Then open the file from one of the available options if possible.</string>
<string name="ReadOnlyReason_ReadOnlyFlag">The read-only flag is set. Remove this flag if you want to make changes to the database.</string>
<string name="ReadOnlyReason_ReadOnlyKitKat">Writing is not possible because of restrictions introduced in Android KitKat. If you want to make changes to the database, close the database and select Change database. Then open the file using System file picker.</string>
<string name="AddCustomIcon">Add icon from file...</string>
<string name="CopyingFile">Copying file...</string>