mirror of
https://github.com/moparisthebest/keepass2android
synced 2024-12-22 23:18:48 -05:00
SelectStorageLocationActivity handles read-only/temporary cases (first implementation, untested)
This commit is contained in:
parent
49c4fa5b05
commit
2593119dec
@ -20,7 +20,7 @@
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>False</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;EXCLUDE_TWOFISH;EXCLUDE_KEYBOARD;EXCLUDE_FILECHOOSER;EXCLUDE_JAVAFILESTORAGE;INCLUDE_KEYTRANSFORM</DefineConstants>
|
||||
<DefineConstants>DEBUG;EXCLUDE_TWOFISH;EXCLUDE_KEYBOARD;INCLUDE_FILECHOOSER;EXCLUDE_JAVAFILESTORAGE;INCLUDE_KEYTRANSFORM</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>False</ConsolePause>
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -67,6 +67,7 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="TestAndroidContentFileStorage.cs" />
|
||||
<Compile Include="TestIntentsAndBundles.cs" />
|
||||
<Compile Include="ProgressDialogStub.cs" />
|
||||
<Compile Include="TestBase.cs" />
|
||||
|
@ -20,7 +20,10 @@ namespace Kp2aUnitTests
|
||||
// Run all tests from this assembly
|
||||
//runner.AddTests(Assembly.GetExecutingAssembly());
|
||||
//runner.AddTests(typeof(TestLoadDb).GetMethod("TestLoadKdb1WithKeyfileByDirectCall"));
|
||||
runner.AddTests(typeof(TestLoadDb).GetMethod("TestLoadKdb1WithKeyfileOnly"));
|
||||
//runner.AddTests(typeof(TestLoadDb).GetMethod("TestLoadKdb1WithKeyfileOnly"));
|
||||
|
||||
|
||||
runner.AddTests(new List<Type> { typeof(TestBuiltInFileStorage) });
|
||||
//runner.AddTests(new List<Type> { typeof(TestSynchronizeCachedDatabase)});
|
||||
//runner.AddTests(typeof(TestLoadDb).GetMethod("LoadErrorWithCertificateTrustFailure"));
|
||||
//runner.AddTests(typeof(TestLoadDb).GetMethod("LoadWithAcceptedCertificateTrustFailure"));
|
||||
|
@ -183,5 +183,15 @@ namespace Kp2aUnitTests
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsPermanentLocation(IOConnectionInfo ioc)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsReadOnly(IOConnectionInfo ioc)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -167,7 +167,7 @@ public class ImporterV3 {
|
||||
hdr.loadFromFile(filebuf, 0 );
|
||||
|
||||
if( (hdr.signature1 != PwDbHeader.PWM_DBSIG_1) || (hdr.signature2 != PwDbHeaderV3.DBSIG_2) ) {
|
||||
throw new InvalidDBSignatureException();
|
||||
throw new InvalidDBSignatureException("Invalid database signature!");
|
||||
}
|
||||
|
||||
if( !hdr.matchesVersion() ) {
|
||||
@ -230,7 +230,7 @@ public class ImporterV3 {
|
||||
} catch (IllegalBlockSizeException e1) {
|
||||
throw new IOException("Invalid block size");
|
||||
} catch (BadPaddingException e1) {
|
||||
throw new InvalidPasswordException();
|
||||
throw new InvalidPasswordException("Invalid key!");
|
||||
}
|
||||
|
||||
// Copy decrypted data for testing
|
||||
@ -251,7 +251,7 @@ public class ImporterV3 {
|
||||
if( ! Arrays.equals(hash, hdr.contentsHash) ) {
|
||||
|
||||
Log.w("KeePassDroid","Database file did not decrypt correctly. (checksum code is broken)");
|
||||
throw new InvalidPasswordException();
|
||||
throw new InvalidPasswordException("Invalid key!");
|
||||
}
|
||||
|
||||
// Import all groups
|
||||
|
172
src/keepass2android/Resources/Resource.designer.cs
generated
172
src/keepass2android/Resources/Resource.designer.cs
generated
@ -3296,6 +3296,9 @@ namespace keepass2android
|
||||
// aapt resource value: 0x7f070204
|
||||
public const int BinaryDirectory_title = 2131165700;
|
||||
|
||||
// aapt resource value: 0x7f0702c5
|
||||
public const int CancelReadOnly = 2131165893;
|
||||
|
||||
// aapt resource value: 0x7f07026a
|
||||
public const int CannotMoveGroupHere = 2131165802;
|
||||
|
||||
@ -3305,56 +3308,56 @@ namespace keepass2android
|
||||
// aapt resource value: 0x7f0702bb
|
||||
public const int CertificateWarning = 2131165883;
|
||||
|
||||
// aapt resource value: 0x7f0702d8
|
||||
public const int ChangeLog = 2131165912;
|
||||
|
||||
// aapt resource value: 0x7f0702d7
|
||||
public const int ChangeLog_0_7 = 2131165911;
|
||||
|
||||
// aapt resource value: 0x7f0702d5
|
||||
public const int ChangeLog_0_8 = 2131165909;
|
||||
|
||||
// aapt resource value: 0x7f0702d4
|
||||
public const int ChangeLog_0_8_1 = 2131165908;
|
||||
|
||||
// aapt resource value: 0x7f0702d3
|
||||
public const int ChangeLog_0_8_2 = 2131165907;
|
||||
|
||||
// aapt resource value: 0x7f0702d2
|
||||
public const int ChangeLog_0_8_3 = 2131165906;
|
||||
|
||||
// aapt resource value: 0x7f0702d1
|
||||
public const int ChangeLog_0_8_4 = 2131165905;
|
||||
|
||||
// aapt resource value: 0x7f0702d0
|
||||
public const int ChangeLog = 2131165904;
|
||||
public const int ChangeLog_0_8_5 = 2131165904;
|
||||
|
||||
// aapt resource value: 0x7f0702cf
|
||||
public const int ChangeLog_0_7 = 2131165903;
|
||||
|
||||
// aapt resource value: 0x7f0702cd
|
||||
public const int ChangeLog_0_8 = 2131165901;
|
||||
|
||||
// aapt resource value: 0x7f0702cc
|
||||
public const int ChangeLog_0_8_1 = 2131165900;
|
||||
|
||||
// aapt resource value: 0x7f0702cb
|
||||
public const int ChangeLog_0_8_2 = 2131165899;
|
||||
|
||||
// aapt resource value: 0x7f0702ca
|
||||
public const int ChangeLog_0_8_3 = 2131165898;
|
||||
|
||||
// aapt resource value: 0x7f0702c9
|
||||
public const int ChangeLog_0_8_4 = 2131165897;
|
||||
|
||||
// aapt resource value: 0x7f0702c8
|
||||
public const int ChangeLog_0_8_5 = 2131165896;
|
||||
|
||||
// aapt resource value: 0x7f0702c7
|
||||
public const int ChangeLog_0_8_6 = 2131165895;
|
||||
|
||||
// aapt resource value: 0x7f0702c6
|
||||
public const int ChangeLog_0_9 = 2131165894;
|
||||
|
||||
// aapt resource value: 0x7f0702c5
|
||||
public const int ChangeLog_0_9_1 = 2131165893;
|
||||
|
||||
// aapt resource value: 0x7f0702c4
|
||||
public const int ChangeLog_0_9_2 = 2131165892;
|
||||
|
||||
// aapt resource value: 0x7f0702c3
|
||||
public const int ChangeLog_0_9_3 = 2131165891;
|
||||
|
||||
// aapt resource value: 0x7f0702c2
|
||||
public const int ChangeLog_0_9_3_r5 = 2131165890;
|
||||
|
||||
// aapt resource value: 0x7f0702c1
|
||||
public const int ChangeLog_0_9_4 = 2131165889;
|
||||
public const int ChangeLog_0_8_6 = 2131165903;
|
||||
|
||||
// aapt resource value: 0x7f0702ce
|
||||
public const int ChangeLog_keptDonate = 2131165902;
|
||||
public const int ChangeLog_0_9 = 2131165902;
|
||||
|
||||
// aapt resource value: 0x7f0702bf
|
||||
public const int ChangeLog_title = 2131165887;
|
||||
// aapt resource value: 0x7f0702cd
|
||||
public const int ChangeLog_0_9_1 = 2131165901;
|
||||
|
||||
// aapt resource value: 0x7f0702cc
|
||||
public const int ChangeLog_0_9_2 = 2131165900;
|
||||
|
||||
// aapt resource value: 0x7f0702cb
|
||||
public const int ChangeLog_0_9_3 = 2131165899;
|
||||
|
||||
// aapt resource value: 0x7f0702ca
|
||||
public const int ChangeLog_0_9_3_r5 = 2131165898;
|
||||
|
||||
// aapt resource value: 0x7f0702c9
|
||||
public const int ChangeLog_0_9_4 = 2131165897;
|
||||
|
||||
// aapt resource value: 0x7f0702d6
|
||||
public const int ChangeLog_keptDonate = 2131165910;
|
||||
|
||||
// aapt resource value: 0x7f0702c7
|
||||
public const int ChangeLog_title = 2131165895;
|
||||
|
||||
// aapt resource value: 0x7f070112
|
||||
public const int CheckForFileChangesOnSave_key = 2131165458;
|
||||
@ -3380,9 +3383,21 @@ namespace keepass2android
|
||||
// aapt resource value: 0x7f070226
|
||||
public const int ClearOfflineCache_title = 2131165734;
|
||||
|
||||
// aapt resource value: 0x7f0702c4
|
||||
public const int ClickOkToSelectLocation = 2131165892;
|
||||
|
||||
// aapt resource value: 0x7f0702c2
|
||||
public const int CopyFileRequired = 2131165890;
|
||||
|
||||
// aapt resource value: 0x7f0702c3
|
||||
public const int CopyFileRequiredForEditing = 2131165891;
|
||||
|
||||
// aapt resource value: 0x7f070117
|
||||
public const int CopyToClipboardNotification_key = 2131165463;
|
||||
|
||||
// aapt resource value: 0x7f0702c6
|
||||
public const int CopyingFile = 2131165894;
|
||||
|
||||
// aapt resource value: 0x7f07025d
|
||||
public const int CouldNotLoadFromRemote = 2131165789;
|
||||
|
||||
@ -3437,6 +3452,15 @@ namespace keepass2android
|
||||
// aapt resource value: 0x7f070104
|
||||
public const int FileHandling_prefs_key = 2131165444;
|
||||
|
||||
// aapt resource value: 0x7f0702c0
|
||||
public const int FileIsReadOnly = 2131165888;
|
||||
|
||||
// aapt resource value: 0x7f0702c1
|
||||
public const int FileIsReadOnlyOnKitkat = 2131165889;
|
||||
|
||||
// aapt resource value: 0x7f0702bf
|
||||
public const int FileIsTemporarilyAvailable = 2131165887;
|
||||
|
||||
// aapt resource value: 0x7f07017a
|
||||
public const int FileNotFound = 2131165562;
|
||||
|
||||
@ -3524,8 +3548,8 @@ namespace keepass2android
|
||||
// aapt resource value: 0x7f070234
|
||||
public const int PreloadDatabaseEnabled_title = 2131165748;
|
||||
|
||||
// aapt resource value: 0x7f0702c0
|
||||
public const int PreviewWarning = 2131165888;
|
||||
// aapt resource value: 0x7f0702c8
|
||||
public const int PreviewWarning = 2131165896;
|
||||
|
||||
// aapt resource value: 0x7f070105
|
||||
public const int QuickUnlockDefaultEnabled_key = 2131165445;
|
||||
@ -4169,11 +4193,11 @@ namespace keepass2android
|
||||
// aapt resource value: 0x7f070145
|
||||
public const int brackets = 2131165509;
|
||||
|
||||
// aapt resource value: 0x7f0702d3
|
||||
public const int browser_intall_text = 2131165907;
|
||||
// aapt resource value: 0x7f0702db
|
||||
public const int browser_intall_text = 2131165915;
|
||||
|
||||
// aapt resource value: 0x7f0702d4
|
||||
public const int building_search_idx = 2131165908;
|
||||
// aapt resource value: 0x7f0702dc
|
||||
public const int building_search_idx = 2131165916;
|
||||
|
||||
// aapt resource value: 0x7f070285
|
||||
public const int button_change_location = 2131165829;
|
||||
@ -4259,14 +4283,14 @@ namespace keepass2android
|
||||
// aapt resource value: 0x7f0700ec
|
||||
public const int db_key = 2131165420;
|
||||
|
||||
// aapt resource value: 0x7f0702d5
|
||||
public const int decrypting_db = 2131165909;
|
||||
// aapt resource value: 0x7f0702dd
|
||||
public const int decrypting_db = 2131165917;
|
||||
|
||||
// aapt resource value: 0x7f0702d6
|
||||
public const int decrypting_entry = 2131165910;
|
||||
// aapt resource value: 0x7f0702de
|
||||
public const int decrypting_entry = 2131165918;
|
||||
|
||||
// aapt resource value: 0x7f0702d7
|
||||
public const int default_checkbox = 2131165911;
|
||||
// aapt resource value: 0x7f0702df
|
||||
public const int default_checkbox = 2131165919;
|
||||
|
||||
// aapt resource value: 0x7f0700de
|
||||
public const int default_file_path = 2131165406;
|
||||
@ -4289,8 +4313,8 @@ namespace keepass2android
|
||||
// aapt resource value: 0x7f0700f3
|
||||
public const int design_key = 2131165427;
|
||||
|
||||
// aapt resource value: 0x7f0702d1
|
||||
public const int design_title = 2131165905;
|
||||
// aapt resource value: 0x7f0702d9
|
||||
public const int design_title = 2131165913;
|
||||
|
||||
// aapt resource value: 0x7f070152
|
||||
public const int digits = 2131165522;
|
||||
@ -4352,8 +4376,8 @@ namespace keepass2android
|
||||
// aapt resource value: 0x7f070156
|
||||
public const int entry_accessed = 2131165526;
|
||||
|
||||
// aapt resource value: 0x7f0702d8
|
||||
public const int entry_and_or = 2131165912;
|
||||
// aapt resource value: 0x7f0702e0
|
||||
public const int entry_and_or = 2131165920;
|
||||
|
||||
// aapt resource value: 0x7f070168
|
||||
public const int entry_binaries = 2131165544;
|
||||
@ -4409,8 +4433,8 @@ namespace keepass2android
|
||||
// aapt resource value: 0x7f07028d
|
||||
public const int error_adding_keyfile = 2131165837;
|
||||
|
||||
// aapt resource value: 0x7f0702d9
|
||||
public const int error_arc4 = 2131165913;
|
||||
// aapt resource value: 0x7f0702e1
|
||||
public const int error_arc4 = 2131165921;
|
||||
|
||||
// aapt resource value: 0x7f070169
|
||||
public const int error_can_not_handle_uri = 2131165545;
|
||||
@ -4424,8 +4448,8 @@ namespace keepass2android
|
||||
// aapt resource value: 0x7f07016c
|
||||
public const int error_database_exists = 2131165548;
|
||||
|
||||
// aapt resource value: 0x7f0702d2
|
||||
public const int error_database_settings = 2131165906;
|
||||
// aapt resource value: 0x7f0702da
|
||||
public const int error_database_settings = 2131165914;
|
||||
|
||||
// aapt resource value: 0x7f07016d
|
||||
public const int error_database_settinoverrgs = 2131165549;
|
||||
@ -4454,8 +4478,8 @@ namespace keepass2android
|
||||
// aapt resource value: 0x7f070174
|
||||
public const int error_nopass = 2131165556;
|
||||
|
||||
// aapt resource value: 0x7f0702da
|
||||
public const int error_out_of_memory = 2131165914;
|
||||
// aapt resource value: 0x7f0702e2
|
||||
public const int error_out_of_memory = 2131165922;
|
||||
|
||||
// aapt resource value: 0x7f070175
|
||||
public const int error_pass_gen_type = 2131165557;
|
||||
@ -4466,8 +4490,8 @@ namespace keepass2android
|
||||
// aapt resource value: 0x7f070177
|
||||
public const int error_rounds_not_number = 2131165559;
|
||||
|
||||
// aapt resource value: 0x7f0702db
|
||||
public const int error_rounds_too_large = 2131165915;
|
||||
// aapt resource value: 0x7f0702e3
|
||||
public const int error_rounds_too_large = 2131165923;
|
||||
|
||||
// aapt resource value: 0x7f07020f
|
||||
public const int error_string_key = 2131165711;
|
||||
@ -4655,11 +4679,11 @@ namespace keepass2android
|
||||
// aapt resource value: 0x7f0701d6
|
||||
public const int insert_element_here = 2131165654;
|
||||
|
||||
// aapt resource value: 0x7f0702dc
|
||||
public const int install_from_market = 2131165916;
|
||||
// aapt resource value: 0x7f0702e4
|
||||
public const int install_from_market = 2131165924;
|
||||
|
||||
// aapt resource value: 0x7f0702dd
|
||||
public const int install_from_website = 2131165917;
|
||||
// aapt resource value: 0x7f0702e5
|
||||
public const int install_from_website = 2131165925;
|
||||
|
||||
// aapt resource value: 0x7f07018c
|
||||
public const int invalid_algorithm = 2131165580;
|
||||
@ -4874,8 +4898,8 @@ namespace keepass2android
|
||||
// aapt resource value: 0x7f0701a6
|
||||
public const int menu_hide_password = 2131165606;
|
||||
|
||||
// aapt resource value: 0x7f0702de
|
||||
public const int menu_homepage = 2131165918;
|
||||
// aapt resource value: 0x7f0702e6
|
||||
public const int menu_homepage = 2131165926;
|
||||
|
||||
// aapt resource value: 0x7f0701a7
|
||||
public const int menu_lock = 2131165607;
|
||||
|
@ -475,6 +475,17 @@
|
||||
|
||||
<string name="killed_by_os">Sorry! Keepass2Android was killed by the Android OS! For security reasons, Keepass2Android did not persist your selected credentials on disk, so you need to re-open your database. Note: This should happen only very rarely. If it does, please drop me a message at crocoapps@gmail.com.</string>
|
||||
|
||||
|
||||
<string name="FileIsTemporarilyAvailable">The file is only temporarily available for Keepass2Android.</string>
|
||||
<string name="FileIsReadOnly">The file you selected is read-only.</string>
|
||||
<string name="FileIsReadOnlyOnKitkat">The file you selected is read-only for Keepass2Android due to restrictions on Android 4.4+.</string>
|
||||
<string name="CopyFileRequired">To use it, you must copy it to another location.</string>
|
||||
<string name="CopyFileRequiredForEditing">To edit it, you must copy the file to another location.</string>
|
||||
<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="CopyingFile">Copying file...</string>
|
||||
|
||||
<string name="ChangeLog_title">Change log</string>
|
||||
|
||||
<string name="PreviewWarning">Please note! This is a preview release and might come with some flaws! If you experience *anything* unexpected, please let me know (on Codeplex or by email).</string>
|
||||
|
@ -9,6 +9,7 @@ using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Group.Pals.Android.Lib.UI.Filechooser.Utils.UI;
|
||||
using KeePassLib.Serialization;
|
||||
using keepass2android.Io;
|
||||
using Environment = Android.OS.Environment;
|
||||
@ -16,11 +17,24 @@ using Environment = Android.OS.Environment;
|
||||
namespace keepass2android
|
||||
{
|
||||
[Activity(Label = "")]
|
||||
public class SelectStorageLocationActivity : Activity
|
||||
public class SelectStorageLocationActivity : Activity, IDialogInterfaceOnDismissListener
|
||||
{
|
||||
private ActivityDesign _design;
|
||||
private bool _isRecreated;
|
||||
private const int RequestCodeFileStorageSelection = 983713;
|
||||
private IOConnectionInfo _selectedIoc;
|
||||
private const string BundleKeySelectedIoc = "BundleKeySelectedIoc";
|
||||
private const int RequestCodeFileStorageSelectionForPrimarySelect = 983713;
|
||||
private const int RequestCodeFileStorageSelectionForCopyToWritableLocation = 983714;
|
||||
private const int RequestCodeFileFileBrowseForWritableLocation = 983715;
|
||||
|
||||
public enum WritableRequirements
|
||||
{
|
||||
ReadOnly = 0,
|
||||
WriteDesired = 1,
|
||||
WriteDemanded = 2
|
||||
}
|
||||
|
||||
public const string ExtraKeyWritableRequirements = "EXTRA_KEY_WRITABLE_REQUIREMENTS";
|
||||
|
||||
public SelectStorageLocationActivity()
|
||||
{
|
||||
@ -36,12 +50,12 @@ namespace keepass2android
|
||||
|
||||
Kp2aLog.Log("SelectStorageLocationActivity.OnCreate");
|
||||
|
||||
IsForSave = Intent.GetBooleanExtra(FileStorageSetupDefs.ExtraIsForSave, false);
|
||||
if (IsForSave)
|
||||
|
||||
if (IsStorageSelectionForSave)
|
||||
{
|
||||
throw new Exception("save is not yet implemented. In StartSelectFile, no handler for onCreate is passed.");
|
||||
}
|
||||
|
||||
|
||||
bool allowThirdPartyGet = Intent.GetBooleanExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, false);
|
||||
bool allowThirdPartySend = Intent.GetBooleanExtra(FileStorageSelectionActivity.AllowThirdPartyAppSend, false);
|
||||
if (bundle == null)
|
||||
@ -49,6 +63,9 @@ namespace keepass2android
|
||||
else
|
||||
{
|
||||
State = (Bundle)bundle.Clone();
|
||||
var selectedIocString = bundle.GetString(BundleKeySelectedIoc, null);
|
||||
if (selectedIocString != null)
|
||||
_selectedIoc = IOConnectionInfo.UnserializeFromString(selectedIocString);
|
||||
_isRecreated = true;
|
||||
}
|
||||
|
||||
@ -57,7 +74,7 @@ namespace keepass2android
|
||||
Intent intent = new Intent(this, typeof(FileStorageSelectionActivity));
|
||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, allowThirdPartyGet);
|
||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppSend, allowThirdPartySend);
|
||||
StartActivityForResult(intent, RequestCodeFileStorageSelection);
|
||||
StartActivityForResult(intent, RequestCodeFileStorageSelectionForPrimarySelect);
|
||||
}
|
||||
|
||||
|
||||
@ -65,7 +82,10 @@ namespace keepass2android
|
||||
|
||||
protected Bundle State { get; set; }
|
||||
|
||||
protected bool IsForSave { get; set; }
|
||||
protected bool IsStorageSelectionForSave
|
||||
{
|
||||
get { return Intent.GetBooleanExtra(FileStorageSetupDefs.ExtraIsForSave, false); }
|
||||
}
|
||||
|
||||
|
||||
protected override void OnSaveInstanceState(Bundle outState)
|
||||
@ -73,6 +93,8 @@ namespace keepass2android
|
||||
base.OnSaveInstanceState(outState);
|
||||
|
||||
outState.PutAll(State);
|
||||
if (_selectedIoc != null)
|
||||
outState.PutString(BundleKeySelectedIoc, IOConnectionInfo.SerializeToString(_selectedIoc));
|
||||
}
|
||||
|
||||
protected override void OnResume()
|
||||
@ -84,8 +106,14 @@ namespace keepass2android
|
||||
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
|
||||
{
|
||||
base.OnActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == RequestCodeFileStorageSelection)
|
||||
if ((requestCode == RequestCodeFileStorageSelectionForPrimarySelect) || ((requestCode == RequestCodeFileStorageSelectionForCopyToWritableLocation)))
|
||||
{
|
||||
int browseRequestCode = Intents.RequestCodeFileBrowseForOpen;
|
||||
if (requestCode == RequestCodeFileStorageSelectionForCopyToWritableLocation)
|
||||
{
|
||||
browseRequestCode = RequestCodeFileFileBrowseForWritableLocation;
|
||||
}
|
||||
|
||||
if (resultCode == KeePass.ExitFileStorageSelectionOk)
|
||||
{
|
||||
|
||||
@ -97,45 +125,55 @@ namespace keepass2android
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isForSave = (requestCode == RequestCodeFileStorageSelectionForPrimarySelect) ?
|
||||
IsStorageSelectionForSave : true;
|
||||
|
||||
App.Kp2a.GetFileStorage(protocolId).StartSelectFile(new FileStorageSetupInitiatorActivity(this,
|
||||
OnActivityResult,
|
||||
defaultPath =>
|
||||
{
|
||||
{
|
||||
if (defaultPath.StartsWith("sftp://"))
|
||||
Util.ShowSftpDialog(this, OnReceivedSftpData, ReturnCancel);
|
||||
Util.ShowSftpDialog(this, filename => OnReceivedSftpData(filename, browseRequestCode, isForSave), ReturnCancel);
|
||||
else
|
||||
Util.ShowFilenameDialog(this, OnOpenButton, null, ReturnCancel, false, defaultPath, GetString(Resource.String.enter_filename_details_url),
|
||||
Intents.RequestCodeFileBrowseForOpen);
|
||||
//todo oncreate nur wenn for save?
|
||||
Util.ShowFilenameDialog(this, filename => OnOpenButton(filename, browseRequestCode),
|
||||
filename => OnOpenButton(filename, browseRequestCode),
|
||||
ReturnCancel, false, defaultPath, GetString(Resource.String.enter_filename_details_url),
|
||||
browseRequestCode);
|
||||
}
|
||||
), false, 0, protocolId);
|
||||
), isForSave, browseRequestCode, protocolId);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (resultCode == (Result)FileStorageResults.FileChooserPrepared)
|
||||
{
|
||||
IOConnectionInfo ioc = new IOConnectionInfo();
|
||||
PasswordActivity.SetIoConnectionFromIntent(ioc, data);
|
||||
#if !EXCLUDE_FILECHOOSER
|
||||
StartFileChooser(ioc.Path);
|
||||
#else
|
||||
ReturnIoc(new IOConnectionInfo { Path = "/mnt/sdcard/keepass/yubi.kdbx" });
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if ((resultCode == Result.Canceled) && (data != null) && (data.HasExtra("EXTRA_ERROR_MESSAGE")))
|
||||
{
|
||||
Toast.MakeText(this, data.GetStringExtra("EXTRA_ERROR_MESSAGE"), ToastLength.Long).Show();
|
||||
}
|
||||
ReturnCancel();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (requestCode == Intents.RequestCodeFileBrowseForOpen)
|
||||
|
||||
if ((requestCode == Intents.RequestCodeFileBrowseForOpen) || (requestCode == RequestCodeFileFileBrowseForWritableLocation))
|
||||
{
|
||||
if (resultCode == (Result)FileStorageResults.FileChooserPrepared)
|
||||
{
|
||||
IOConnectionInfo ioc = new IOConnectionInfo();
|
||||
PasswordActivity.SetIoConnectionFromIntent(ioc, data);
|
||||
#if !EXCLUDE_FILECHOOSER
|
||||
bool isForSave = (requestCode == RequestCodeFileFileBrowseForWritableLocation) ?
|
||||
true : IsStorageSelectionForSave ;
|
||||
|
||||
StartFileChooser(ioc.Path, requestCode, isForSave);
|
||||
#else
|
||||
IocSelected(new IOConnectionInfo { Path = "/mnt/sdcard/keepass/yubi.kdbx" }, requestCode);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if ((resultCode == Result.Canceled) && (data != null) && (data.HasExtra("EXTRA_ERROR_MESSAGE")))
|
||||
{
|
||||
Toast.MakeText(this, data.GetStringExtra("EXTRA_ERROR_MESSAGE"), ToastLength.Long).Show();
|
||||
}
|
||||
|
||||
if (resultCode == Result.Ok)
|
||||
{
|
||||
string filename = Util.IntentToFilename(data, this);
|
||||
@ -152,13 +190,13 @@ namespace keepass2android
|
||||
Path = filename
|
||||
};
|
||||
|
||||
ReturnIoc(ioc);
|
||||
IocSelected(ioc, requestCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data.Data.Scheme == "content")
|
||||
{
|
||||
ReturnIoc(IOConnectionInfo.FromPath(data.DataString));
|
||||
IocSelected(IOConnectionInfo.FromPath(data.DataString), requestCode);
|
||||
|
||||
}
|
||||
else
|
||||
@ -189,28 +227,154 @@ namespace keepass2android
|
||||
Finish();
|
||||
}
|
||||
|
||||
private void ReturnIoc(IOConnectionInfo ioc)
|
||||
private void IocSelected(IOConnectionInfo ioc, int requestCode)
|
||||
{
|
||||
if (requestCode == RequestCodeFileFileBrowseForWritableLocation)
|
||||
{
|
||||
IocForCopySelected(ioc);
|
||||
}
|
||||
else if (requestCode == Intents.RequestCodeFileBrowseForOpen)
|
||||
{
|
||||
PrimaryIocSelected(ioc);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
throw new Exception("invalid request code!");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void IocForCopySelected(IOConnectionInfo targetIoc)
|
||||
{
|
||||
new keepass2android.Utils.SimpleLoadingDialog(this, GetString(Resource.String.CopyingFile), false,
|
||||
() =>
|
||||
{
|
||||
IOConnectionInfo sourceIoc = _selectedIoc;
|
||||
|
||||
try
|
||||
{
|
||||
CopyFile(targetIoc, sourceIoc);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
Toast.MakeText(this, App.Kp2a.GetResourceString(UiStringKey.ErrorOcurred) + " " + e.Message, ToastLength.Long).Show();
|
||||
ReturnCancel();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
return () => {ReturnOk(targetIoc); };
|
||||
}
|
||||
).Execute(new Object[] {});
|
||||
}
|
||||
|
||||
private static void CopyFile(IOConnectionInfo targetIoc, IOConnectionInfo sourceIoc)
|
||||
{
|
||||
IFileStorage sourceStorage = App.Kp2a.GetFileStorage(sourceIoc);
|
||||
IFileStorage targetStorage = App.Kp2a.GetFileStorage(targetIoc);
|
||||
|
||||
using (
|
||||
var writeTransaction = targetStorage.OpenWriteTransaction(targetIoc,
|
||||
App.Kp2a.GetBooleanPreference(
|
||||
PreferenceKey.UseFileTransactions)))
|
||||
{
|
||||
using (var writeStream = writeTransaction.OpenFile())
|
||||
{
|
||||
sourceStorage.OpenFileForRead(sourceIoc).CopyTo(writeStream);
|
||||
}
|
||||
writeTransaction.CommitWrite();
|
||||
}
|
||||
}
|
||||
|
||||
private void PrimaryIocSelected(IOConnectionInfo ioc)
|
||||
{
|
||||
if (!App.Kp2a.GetFileStorage(ioc).IsPermanentLocation(ioc))
|
||||
{
|
||||
new AlertDialog.Builder(this)
|
||||
.SetPositiveButton(Android.Resource.String.Ok, (sender, args) => { MoveToWritableLocation(ioc); })
|
||||
.SetMessage(Resources.GetString(Resource.String.FileIsTemporarilyAvailable) + " "
|
||||
+ Resources.GetString(Resource.String.CopyFileRequired) + " "
|
||||
+ Resources.GetString(Resource.String.ClickOkToSelectLocation))
|
||||
.SetCancelable(false)
|
||||
.SetNegativeButton(Android.Resource.String.Cancel, (sender, args) => { ReturnCancel(); })
|
||||
//.SetOnDismissListener(this)
|
||||
.Create()
|
||||
.Show();
|
||||
return;
|
||||
}
|
||||
var filestorage = App.Kp2a.GetFileStorage(ioc);
|
||||
|
||||
if ((RequestedWritableRequirements != WritableRequirements.ReadOnly) && (filestorage.IsReadOnly(ioc)))
|
||||
{
|
||||
string readOnlyExplanation = Resources.GetString(Resource.String.FileIsReadOnly);
|
||||
BuiltInFileStorage builtInFileStorage = filestorage as BuiltInFileStorage;
|
||||
if (builtInFileStorage != null)
|
||||
{
|
||||
if (builtInFileStorage.IsReadOnlyBecauseKitkatRestrictions(ioc))
|
||||
readOnlyExplanation = Resources.GetString(Resource.String.FileIsReadOnlyOnKitkat);
|
||||
}
|
||||
new AlertDialog.Builder(this)
|
||||
.SetPositiveButton(Android.Resource.String.Ok, (sender, args) => { MoveToWritableLocation(ioc); })
|
||||
.SetCancelable(false)
|
||||
.SetNegativeButton(Android.Resource.String.Cancel, (sender, args) => { ReturnCancel(); })
|
||||
//.SetOnDismissListener(this)
|
||||
.SetMessage(readOnlyExplanation + " "
|
||||
+ (RequestedWritableRequirements == WritableRequirements.WriteDemanded ?
|
||||
Resources.GetString(Resource.String.CopyFileRequired)
|
||||
: Resources.GetString(Resource.String.CopyFileRequiredForEditing))
|
||||
+ " "
|
||||
+ Resources.GetString(Resource.String.ClickOkToSelectLocation))
|
||||
.Create()
|
||||
.Show();
|
||||
return;
|
||||
}
|
||||
ReturnOk(ioc);
|
||||
}
|
||||
|
||||
private void ReturnOk(IOConnectionInfo ioc)
|
||||
{
|
||||
Intent intent = new Intent();
|
||||
PasswordActivity.PutIoConnectionToIntent(ioc, intent);
|
||||
SetResult(Result.Ok, intent);
|
||||
Finish();
|
||||
}
|
||||
|
||||
private WritableRequirements RequestedWritableRequirements
|
||||
{
|
||||
get { return (WritableRequirements) Intent.GetIntExtra(ExtraKeyWritableRequirements, (int)WritableRequirements.ReadOnly); }
|
||||
}
|
||||
|
||||
private void MoveToWritableLocation(IOConnectionInfo ioc)
|
||||
{
|
||||
_selectedIoc = ioc;
|
||||
|
||||
Intent intent = new Intent(this, typeof(FileStorageSelectionActivity));
|
||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, false);
|
||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppSend, false);
|
||||
|
||||
StartActivityForResult(intent, RequestCodeFileStorageSelectionForCopyToWritableLocation);
|
||||
|
||||
}
|
||||
|
||||
private bool OnReceivedSftpData(string filename)
|
||||
private bool OnReceivedSftpData(string filename, int requestCode, bool isForSave)
|
||||
{
|
||||
IOConnectionInfo ioc = new IOConnectionInfo { Path = filename };
|
||||
#if !EXCLUDE_FILECHOOSER
|
||||
StartFileChooser(ioc.Path);
|
||||
StartFileChooser(ioc.Path, requestCode, isForSave);
|
||||
#else
|
||||
ReturnIoc(ioc);
|
||||
IocSelected(ioc, requestCode);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !EXCLUDE_FILECHOOSER
|
||||
private void StartFileChooser(string defaultPath)
|
||||
private void StartFileChooser(string defaultPath, int requestCode, bool forSave)
|
||||
{
|
||||
Kp2aLog.Log("FSA: defaultPath="+defaultPath);
|
||||
string fileProviderAuthority = FileChooserFileProvider.TheAuthority;
|
||||
@ -221,24 +385,35 @@ namespace keepass2android
|
||||
Intent i = Keepass2android.Kp2afilechooser.Kp2aFileChooserBridge.GetLaunchFileChooserIntent(this, fileProviderAuthority,
|
||||
defaultPath);
|
||||
|
||||
StartActivityForResult(i, Intents.RequestCodeFileBrowseForOpen);
|
||||
|
||||
if (forSave)
|
||||
{
|
||||
i.PutExtra("group.pals.android.lib.ui.filechooser.FileChooserActivity.save_dialog", true);
|
||||
i.PutExtra("group.pals.android.lib.ui.filechooser.FileChooserActivity.default_file_ext", "kdbx");
|
||||
}
|
||||
StartActivityForResult(i, requestCode);
|
||||
}
|
||||
|
||||
#endif
|
||||
private bool OnOpenButton(String fileName)
|
||||
private bool OnOpenButton(String fileName, int requestCode)
|
||||
{
|
||||
|
||||
|
||||
IOConnectionInfo ioc = new IOConnectionInfo
|
||||
{
|
||||
Path = fileName
|
||||
};
|
||||
|
||||
ReturnIoc(ioc);
|
||||
IocSelected(ioc, requestCode);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public void OnDismiss(IDialogInterface dialog)
|
||||
{
|
||||
// ReturnCancel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -9,13 +9,13 @@ using Object = Java.Lang.Object;
|
||||
|
||||
namespace keepass2android.Utils
|
||||
{
|
||||
public class LoadingDialog<TParams, TProgress, TResult> : AsyncTask<TParams, TProgress, TResult>
|
||||
public class LoadingDialog<TParams, TProgress, TResult> : AsyncTask<TParams, TProgress, TResult>
|
||||
{
|
||||
private readonly Context _context;
|
||||
private readonly string _message;
|
||||
private readonly bool _cancelable;
|
||||
readonly Func<Object[], Object> _doInBackground;
|
||||
readonly Action<Object> _onPostExecute;
|
||||
private readonly Func<Object[], Object> _doInBackground;
|
||||
private readonly Action<Object> _onPostExecute;
|
||||
|
||||
private ProgressDialog mDialog;
|
||||
/**
|
||||
@ -29,13 +29,14 @@ namespace keepass2android.Utils
|
||||
|
||||
private Exception mLastException;
|
||||
|
||||
|
||||
public LoadingDialog(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
|
||||
|
||||
public LoadingDialog(IntPtr javaReference, JniHandleOwnership transfer)
|
||||
: base(javaReference, transfer)
|
||||
{
|
||||
}
|
||||
|
||||
public LoadingDialog(Context context, string message, bool cancelable, Func<Object[], Object> doInBackground,
|
||||
Action<Object> onPostExecute)
|
||||
public LoadingDialog(Context context, string message, bool cancelable, Func<Object[], Object> doInBackground,
|
||||
Action<Object> onPostExecute)
|
||||
{
|
||||
_context = context;
|
||||
_message = message;
|
||||
@ -58,7 +59,8 @@ namespace keepass2android.Utils
|
||||
}
|
||||
}
|
||||
|
||||
public LoadingDialog(Context context, bool cancelable, Func<Object[], Object> doInBackground, Action<Object> onPostExecute)
|
||||
public LoadingDialog(Context context, bool cancelable, Func<Object[], Object> doInBackground,
|
||||
Action<Object> onPostExecute)
|
||||
{
|
||||
_message = context.GetString(Resource.String.loading);
|
||||
_context = context;
|
||||
@ -89,32 +91,41 @@ namespace keepass2android.Utils
|
||||
}
|
||||
|
||||
}
|
||||
, mDelayTime);
|
||||
, mDelayTime);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* If you override this method, you must call {@code super.onCancelled()} at
|
||||
* beginning of the method.
|
||||
*/
|
||||
protected override void OnCancelled() {
|
||||
|
||||
protected override void OnCancelled()
|
||||
{
|
||||
DoFinish();
|
||||
base.OnCancelled();
|
||||
}// onCancelled()
|
||||
}
|
||||
|
||||
private void DoFinish() {
|
||||
// onCancelled()
|
||||
|
||||
private void DoFinish()
|
||||
{
|
||||
mFinished = true;
|
||||
try {
|
||||
try
|
||||
{
|
||||
/*
|
||||
* Sometime the activity has been finished before we dismiss this
|
||||
* dialog, it will raise error.
|
||||
*/
|
||||
mDialog.Dismiss();
|
||||
} catch (Exception e)
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Kp2aLog.Log(e.ToString());
|
||||
}
|
||||
}// doFinish()
|
||||
}
|
||||
|
||||
// doFinish()
|
||||
|
||||
|
||||
/**
|
||||
@ -124,18 +135,26 @@ namespace keepass2android.Utils
|
||||
* @param t
|
||||
* {@link Throwable}
|
||||
*/
|
||||
protected void SetLastException(Exception e) {
|
||||
|
||||
protected void SetLastException(Exception e)
|
||||
{
|
||||
mLastException = e;
|
||||
}// setLastException()
|
||||
}
|
||||
|
||||
// setLastException()
|
||||
|
||||
/**
|
||||
* Gets last exception.
|
||||
*
|
||||
* @return {@link Throwable}
|
||||
*/
|
||||
protected Exception GetLastException() {
|
||||
|
||||
protected Exception GetLastException()
|
||||
{
|
||||
return mLastException;
|
||||
}// getLastException()
|
||||
}
|
||||
|
||||
// getLastException()
|
||||
|
||||
|
||||
protected override Object DoInBackground(params Object[] @params)
|
||||
@ -151,14 +170,47 @@ namespace keepass2android.Utils
|
||||
protected override void OnPostExecute(Object result)
|
||||
{
|
||||
DoFinish();
|
||||
|
||||
|
||||
if (_onPostExecute != null)
|
||||
_onPostExecute(result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class SimpleLoadingDialog : LoadingDialog<object, object, object>
|
||||
{
|
||||
private class BackgroundResult : Object
|
||||
{
|
||||
private readonly Action _onPostExec;
|
||||
|
||||
public BackgroundResult(Action onPostExec)
|
||||
{
|
||||
_onPostExec = onPostExec;
|
||||
}
|
||||
|
||||
public Action OnPostExec
|
||||
{
|
||||
get { return _onPostExec; }
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleLoadingDialog(IntPtr javaReference, JniHandleOwnership transfer)
|
||||
: base(javaReference, transfer)
|
||||
{
|
||||
}
|
||||
|
||||
public SimpleLoadingDialog(Context ctx, string message, bool cancelable, Func<Action> doInBackgroundReturnOnPostExec)
|
||||
: base(ctx, message, cancelable, input =>
|
||||
{ return new BackgroundResult(doInBackgroundReturnOnPostExec()); }
|
||||
, res => { ((BackgroundResult) res).OnPostExec(); })
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -267,10 +267,29 @@ namespace keepass2android
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class CancelListener: Java.Lang.Object, IDialogInterfaceOnCancelListener
|
||||
{
|
||||
private readonly Action _onCancel;
|
||||
|
||||
public CancelListener(Action onCancel)
|
||||
{
|
||||
_onCancel = onCancel;
|
||||
}
|
||||
|
||||
public void OnCancel(IDialogInterface dialog)
|
||||
{
|
||||
_onCancel();
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowFilenameDialog(Activity activity, FileSelectedHandler onOpen, FileSelectedHandler onCreate, Action onCancel, bool showBrowseButton, string defaultFilename, string detailsText, int requestCodeBrowse)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.SetView(activity.LayoutInflater.Inflate(Resource.Layout.file_selection_filename, null));
|
||||
|
||||
if (onCancel != null)
|
||||
builder.SetOnCancelListener(new CancelListener(onCancel));
|
||||
Dialog dialog = builder.Create();
|
||||
dialog.Show();
|
||||
|
||||
@ -308,11 +327,13 @@ namespace keepass2android
|
||||
cancelButton.Click += delegate
|
||||
{
|
||||
dialog.Dismiss();
|
||||
|
||||
if (onCancel != null)
|
||||
onCancel();
|
||||
};
|
||||
|
||||
if (onCancel != null)
|
||||
dialog.SetOnDismissListener(new DismissListener(onCancel));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ImageButton browseButton = (ImageButton) dialog.FindViewById(Resource.Id.browse_button);
|
||||
@ -324,7 +345,7 @@ namespace keepass2android
|
||||
{
|
||||
string filename = ((EditText) dialog.FindViewById(Resource.Id.file_filename)).Text;
|
||||
|
||||
Util.ShowBrowseDialog(activity, requestCodeBrowse, onCreate != null);
|
||||
ShowBrowseDialog(activity, requestCodeBrowse, onCreate != null);
|
||||
|
||||
};
|
||||
|
||||
|
@ -133,6 +133,7 @@ namespace keepass2android
|
||||
Intent intent = new Intent(this, typeof(SelectStorageLocationActivity));
|
||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, true);
|
||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppSend, false);
|
||||
intent.PutExtra(SelectStorageLocationActivity.ExtraKeyWritableRequirements, (int) SelectStorageLocationActivity.WritableRequirements.WriteDesired);
|
||||
intent.PutExtra(FileStorageSetupDefs.ExtraIsForSave, false);
|
||||
StartActivityForResult(intent, RequestCodeSelectIoc);
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;EXCLUDE_TWOFISH;EXCLUDE_KEYBOARD;EXCLUDE_FILECHOOSER;EXCLUDE_JAVAFILESTORAGE;INCLUDE_KEYTRANSFORM</DefineConstants>
|
||||
<DefineConstants>DEBUG;EXCLUDE_TWOFISH;EXCLUDE_KEYBOARD;INCLUDE_FILECHOOSER;EXCLUDE_JAVAFILESTORAGE;INCLUDE_KEYTRANSFORM</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>False</ConsolePause>
|
||||
|
Loading…
Reference in New Issue
Block a user