SelectStorageLocationActivity handles read-only/temporary cases (first implementation, untested)

This commit is contained in:
Philipp Crocoll
2014-11-18 06:24:35 +01:00
parent 49c4fa5b05
commit 2593119dec
17 changed files with 547 additions and 150 deletions

View File

@@ -143,6 +143,18 @@ namespace keepass2android.Io
{
throw new NotImplementedException();
}
public bool IsPermanentLocation(IOConnectionInfo ioc)
{
//on pre-Kitkat devices, content:// is always temporary:
return false;
}
public bool IsReadOnly(IOConnectionInfo ioc)
{
//on pre-Kitkat devices, we can't write content:// files
return true;
}
}
class AndroidContentWriteTransaction : IWriteTransaction

View File

@@ -4,6 +4,7 @@ using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security;
using Android.Content;
using Android.OS;
using Java.Security.Cert;
@@ -290,5 +291,67 @@ namespace keepass2android.Io
res.Path += filename;
return res;
}
public bool IsPermanentLocation(IOConnectionInfo ioc)
{
return true;
}
public bool IsReadOnlyBecauseKitkatRestrictions(IOConnectionInfo ioc)
{
if (IsLocalFileFlaggedReadOnly(ioc))
return false; //it's not read-only because of the restrictions introduced in kitkat
try
{
//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))
{
writer.Close();
return false; //we can write
}
}
catch (Java.IO.IOException)
{
//seems like we can't write to that location even though it's not read-only
return true;
}
}
public bool IsReadOnly(IOConnectionInfo ioc)
{
if (ioc.IsLocalFile())
{
if (IsLocalFileFlaggedReadOnly(ioc))
return true;
if (IsReadOnlyBecauseKitkatRestrictions(ioc))
return true;
return false;
}
//for remote files assume they can be written: (think positive! :-) )
return false;
}
private bool IsLocalFileFlaggedReadOnly(IOConnectionInfo ioc)
{
try
{
return new FileInfo(ioc.Path).IsReadOnly;
}
catch (SecurityException)
{
return true;
}
catch (UnauthorizedAccessException)
{
return true;
}
catch (Exception)
{
return false;
}
}
}
}

View File

@@ -542,6 +542,19 @@ namespace keepass2android.Io
}
public bool IsPermanentLocation(IOConnectionInfo ioc)
{
//even though the cache would be permanent, it's not a good idea to cache a temporary file, so return false in that case:
return _cachedStorage.IsPermanentLocation(ioc);
}
public bool IsReadOnly(IOConnectionInfo ioc)
{
//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);
}
private void StoreFilePath(IOConnectionInfo folderPath, string filename, IOConnectionInfo res)
{
File.WriteAllText(CachedFilePath(GetPseudoIoc(folderPath, filename)) + ".filepath", res.Path);

View File

@@ -149,6 +149,17 @@ namespace keepass2android.Io
/// </summary>
/// The method may throw FileNotFoundException or not in case the file doesn't exist.
IOConnectionInfo GetFilePath(IOConnectionInfo folderPath, string filename);
/// <summary>
/// returns true if it can be expected that this location will be available permanently (in contrast to a cache copy or temporary URI permissions in Android)
/// </summary>
/// 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);
}
public interface IWriteTransaction: IDisposable

View File

@@ -20,7 +20,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;EXCLUDE_TWOFISH;EXCLUDE_KEYBOARD;EXCLUDE_FILECHOOSER;EXCLUDE_JAVAFILESTORAGE;INCLUDE_KEYTRANSFORM</DefineConstants>
<DefineConstants>TRACE;DEBUG;EXCLUDE_TWOFISH;EXCLUDE_KEYBOARD;INCLUDE_FILECHOOSER;EXCLUDE_JAVAFILESTORAGE;INCLUDE_KEYTRANSFORM</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>