mirror of
https://github.com/moparisthebest/keepass2android
synced 2024-11-25 10:42:17 -05:00
moved logic of StorageSelectionActivity to testable base class
added tests for StorageSelectionActivity, fixed bugs if database is read-only, no edit buttons are displayed
This commit is contained in:
parent
2593119dec
commit
415049af7a
@ -41,8 +41,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterKeeWinPlugin", "Maste
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamplePlugin", "SamplePlugin\SamplePlugin.csproj", "{4C1BB6F8-D2CD-49C2-9053-21705681356C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoTypeNeo", "..\..\..\..\..\Dropbox\programmieren\KeepassPlugins\AutoTypeNeo\AutoTypeNeo.csproj", "{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -446,24 +444,6 @@ Global
|
||||
{4C1BB6F8-D2CD-49C2-9053-21705681356C}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{4C1BB6F8-D2CD-49C2-9053-21705681356C}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
||||
{4C1BB6F8-D2CD-49C2-9053-21705681356C}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -474,7 +454,6 @@ Global
|
||||
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C} = {CAC7DBC4-E21F-41E1-B33A-E3A04585F6A3}
|
||||
{BBF77830-BC7D-4F28-A255-A348B5C6A925} = {CAC7DBC4-E21F-41E1-B33A-E3A04585F6A3}
|
||||
{4C1BB6F8-D2CD-49C2-9053-21705681356C} = {CAC7DBC4-E21F-41E1-B33A-E3A04585F6A3}
|
||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B} = {CAC7DBC4-E21F-41E1-B33A-E3A04585F6A3}
|
||||
EndGlobalSection
|
||||
GlobalSection(MonoDevelopProperties) = preSolution
|
||||
StartupItem = keepass2android\keepass2android.csproj
|
||||
|
@ -79,8 +79,17 @@ namespace keepass2android
|
||||
Handler UiThreadHandler { get; }
|
||||
|
||||
IProgressDialog CreateProgressDialog(Context ctx);
|
||||
|
||||
/// <summary>
|
||||
/// returns the file storage for the given ioc. might be a caching file storage
|
||||
/// </summary>
|
||||
IFileStorage GetFileStorage(IOConnectionInfo iocInfo);
|
||||
|
||||
/// <summary>
|
||||
/// returns the file storage for the given ioc. if allowCache=false, no cached file storage is returned
|
||||
/// </summary>
|
||||
IFileStorage GetFileStorage(IOConnectionInfo iocInfo, bool allowCache);
|
||||
|
||||
void TriggerReload(Context context);
|
||||
|
||||
/// <summary>
|
||||
@ -90,5 +99,7 @@ namespace keepass2android
|
||||
//bool OnServerCertificateError(int certificateProblem);
|
||||
|
||||
RemoteCertificateValidationCallback CertificateValidationCallback { get; }
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -80,6 +80,7 @@
|
||||
<Compile Include="Io\SkyDriveFileStorage.cs" />
|
||||
<Compile Include="IProgressDialog.cs" />
|
||||
<Compile Include="PreferenceKey.cs" />
|
||||
<Compile Include="SelectStorageLocationActivityBase.cs" />
|
||||
<Compile Include="UiStringKey.cs" />
|
||||
<Compile Include="database\Database.cs" />
|
||||
<Compile Include="database\edit\ActionOnFinish.cs" />
|
||||
|
318
src/Kp2aBusinessLogic/SelectStorageLocationActivityBase.cs
Normal file
318
src/Kp2aBusinessLogic/SelectStorageLocationActivityBase.cs
Normal file
@ -0,0 +1,318 @@
|
||||
using System;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Widget;
|
||||
using Java.Net;
|
||||
using KeePassLib.Serialization;
|
||||
using keepass2android.Io;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
/// <summary>
|
||||
/// base class for SelectStorageLocationActivity containing testable (non-UI) code
|
||||
/// </summary>
|
||||
public abstract class SelectStorageLocationActivityBase: Activity
|
||||
{
|
||||
public enum WritableRequirements
|
||||
{
|
||||
ReadOnly = 0,
|
||||
WriteDesired = 1,
|
||||
WriteDemanded = 2
|
||||
}
|
||||
|
||||
protected const int RequestCodeFileStorageSelectionForPrimarySelect = 983713;
|
||||
private const int RequestCodeFileStorageSelectionForCopyToWritableLocation = 983714;
|
||||
private const int RequestCodeFileFileBrowseForWritableLocation = 983715;
|
||||
private const int RequestCodeFileBrowseForOpen = 983716;
|
||||
|
||||
|
||||
protected IOConnectionInfo _selectedIoc;
|
||||
private IKp2aApp _app;
|
||||
|
||||
public SelectStorageLocationActivityBase(IKp2aApp app)
|
||||
{
|
||||
_app = app;
|
||||
}
|
||||
|
||||
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
|
||||
{
|
||||
base.OnActivityResult(requestCode, resultCode, data);
|
||||
if ((requestCode == RequestCodeFileStorageSelectionForPrimarySelect) || ((requestCode == RequestCodeFileStorageSelectionForCopyToWritableLocation)))
|
||||
{
|
||||
int browseRequestCode = RequestCodeFileBrowseForOpen;
|
||||
if (requestCode == RequestCodeFileStorageSelectionForCopyToWritableLocation)
|
||||
{
|
||||
browseRequestCode = RequestCodeFileFileBrowseForWritableLocation;
|
||||
}
|
||||
|
||||
if (resultCode == ExitFileStorageSelectionOk)
|
||||
{
|
||||
|
||||
string protocolId = data.GetStringExtra("protocolId");
|
||||
|
||||
if (protocolId == "androidget")
|
||||
{
|
||||
ShowAndroidBrowseDialog(RequestCodeFileBrowseForOpen, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isForSave = (requestCode == RequestCodeFileStorageSelectionForPrimarySelect) ?
|
||||
IsStorageSelectionForSave : true;
|
||||
|
||||
|
||||
StartSelectFile(isForSave, browseRequestCode, protocolId);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
ReturnCancel();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ((requestCode == RequestCodeFileBrowseForOpen) || (requestCode == RequestCodeFileFileBrowseForWritableLocation))
|
||||
{
|
||||
if (resultCode == (Result)FileStorageResults.FileChooserPrepared)
|
||||
{
|
||||
IOConnectionInfo ioc = new IOConnectionInfo();
|
||||
SetIoConnectionFromIntent(ioc, data);
|
||||
bool isForSave = (requestCode == RequestCodeFileFileBrowseForWritableLocation) ?
|
||||
true : IsStorageSelectionForSave;
|
||||
|
||||
StartFileChooser(ioc.Path, requestCode, isForSave);
|
||||
|
||||
return;
|
||||
}
|
||||
if ((resultCode == Result.Canceled) && (data != null) && (data.HasExtra("EXTRA_ERROR_MESSAGE")))
|
||||
{
|
||||
ShowToast(data.GetStringExtra("EXTRA_ERROR_MESSAGE"));
|
||||
}
|
||||
|
||||
if (resultCode == Result.Ok)
|
||||
{
|
||||
string filename = IntentToFilename(data);
|
||||
if (filename != null)
|
||||
{
|
||||
if (filename.StartsWith("file://"))
|
||||
{
|
||||
filename = filename.Substring(7);
|
||||
filename = URLDecoder.Decode(filename);
|
||||
}
|
||||
|
||||
IOConnectionInfo ioc = new IOConnectionInfo
|
||||
{
|
||||
Path = filename
|
||||
};
|
||||
|
||||
IocSelected(ioc, requestCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data.Data.Scheme == "content")
|
||||
{
|
||||
IocSelected(IOConnectionInfo.FromPath(data.DataString), requestCode);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowInvalidSchemeMessage(data.DataString);
|
||||
ReturnCancel();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ReturnCancel();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected abstract void ShowToast(string text);
|
||||
|
||||
protected abstract void ShowInvalidSchemeMessage(string dataString);
|
||||
|
||||
protected abstract string IntentToFilename(Intent data);
|
||||
|
||||
protected abstract void SetIoConnectionFromIntent(IOConnectionInfo ioc, Intent data);
|
||||
|
||||
protected abstract Result ExitFileStorageSelectionOk { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Starts the appropriate file selection process (either manual file select or prepare filechooser + filechooser)
|
||||
/// </summary>
|
||||
/// <param name="isForSave"></param>
|
||||
/// <param name="browseRequestCode"></param>
|
||||
/// <param name="protocolId"></param>
|
||||
protected abstract void StartSelectFile(bool isForSave, int browseRequestCode, string protocolId);
|
||||
|
||||
protected abstract void ShowAndroidBrowseDialog(int requestCode, bool isForSave);
|
||||
|
||||
protected abstract bool IsStorageSelectionForSave { get; }
|
||||
|
||||
|
||||
private void IocSelected(IOConnectionInfo ioc, int requestCode)
|
||||
{
|
||||
if (requestCode == RequestCodeFileFileBrowseForWritableLocation)
|
||||
{
|
||||
IocForCopySelected(ioc);
|
||||
}
|
||||
else if (requestCode == RequestCodeFileBrowseForOpen)
|
||||
{
|
||||
PrimaryIocSelected(ioc);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
throw new Exception("invalid request code!");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void IocForCopySelected(IOConnectionInfo targetIoc)
|
||||
{
|
||||
PerformCopy(() =>
|
||||
{
|
||||
IOConnectionInfo sourceIoc = _selectedIoc;
|
||||
|
||||
try
|
||||
{
|
||||
CopyFile(targetIoc, sourceIoc);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
ShowToast(_app.GetResourceString(UiStringKey.ErrorOcurred) + " " + e.Message);
|
||||
ReturnCancel();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
return () => { ReturnOk(targetIoc); };
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract void PerformCopy(Func<Action> copyAndReturnPostExecute);
|
||||
|
||||
private void MoveToWritableLocation(IOConnectionInfo ioc)
|
||||
{
|
||||
_selectedIoc = ioc;
|
||||
|
||||
StartFileStorageSelection(RequestCodeFileStorageSelectionForCopyToWritableLocation, false, false);
|
||||
|
||||
}
|
||||
|
||||
protected abstract void StartFileStorageSelection(int requestCode,
|
||||
bool allowThirdPartyGet, bool allowThirdPartySend);
|
||||
|
||||
protected bool OnReceivedSftpData(string filename, int requestCode, bool isForSave)
|
||||
{
|
||||
IOConnectionInfo ioc = new IOConnectionInfo { Path = filename };
|
||||
#if !EXCLUDE_FILECHOOSER
|
||||
StartFileChooser(ioc.Path, requestCode, isForSave);
|
||||
#else
|
||||
IocSelected(ioc, requestCode);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract void StartFileChooser(string path, int requestCode, bool isForSave);
|
||||
|
||||
protected bool OnOpenButton(String fileName, int requestCode)
|
||||
{
|
||||
|
||||
|
||||
IOConnectionInfo ioc = new IOConnectionInfo
|
||||
{
|
||||
Path = fileName
|
||||
};
|
||||
|
||||
IocSelected(ioc, requestCode);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected virtual void CopyFile(IOConnectionInfo targetIoc, IOConnectionInfo sourceIoc)
|
||||
{
|
||||
IFileStorage sourceStorage = _app.GetFileStorage(sourceIoc, false); //don't cache source. file won't be used ever again
|
||||
IFileStorage targetStorage = _app.GetFileStorage(targetIoc);
|
||||
|
||||
using (
|
||||
var writeTransaction = targetStorage.OpenWriteTransaction(targetIoc,
|
||||
_app.GetBooleanPreference(
|
||||
PreferenceKey.UseFileTransactions)))
|
||||
{
|
||||
using (var writeStream = writeTransaction.OpenFile())
|
||||
{
|
||||
sourceStorage.OpenFileForRead(sourceIoc).CopyTo(writeStream);
|
||||
}
|
||||
writeTransaction.CommitWrite();
|
||||
}
|
||||
}
|
||||
|
||||
private void PrimaryIocSelected(IOConnectionInfo ioc)
|
||||
{
|
||||
var filestorage = _app.GetFileStorage(ioc, false);
|
||||
if (!filestorage.IsPermanentLocation(ioc))
|
||||
{
|
||||
|
||||
string message = _app.GetResourceString(UiStringKey.FileIsTemporarilyAvailable) + " " + _app.GetResourceString(UiStringKey.CopyFileRequired) + " " + _app.GetResourceString(UiStringKey.ClickOkToSelectLocation);
|
||||
EventHandler<DialogClickEventArgs> onOk = (sender, args) => { MoveToWritableLocation(ioc); };
|
||||
EventHandler<DialogClickEventArgs> onCancel = (sender, args) => { ReturnCancel(); };
|
||||
ShowAlertDialog(message, onOk, onCancel);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ((RequestedWritableRequirements != WritableRequirements.ReadOnly) && (filestorage.IsReadOnly(ioc)))
|
||||
{
|
||||
string readOnlyExplanation = _app.GetResourceString(UiStringKey.FileIsReadOnly);
|
||||
BuiltInFileStorage builtInFileStorage = filestorage as BuiltInFileStorage;
|
||||
if (builtInFileStorage != null)
|
||||
{
|
||||
if (builtInFileStorage.IsReadOnlyBecauseKitkatRestrictions(ioc))
|
||||
readOnlyExplanation = _app.GetResourceString(UiStringKey.FileIsReadOnlyOnKitkat);
|
||||
}
|
||||
EventHandler<DialogClickEventArgs> onOk = (sender, args) => { MoveToWritableLocation(ioc); };
|
||||
EventHandler<DialogClickEventArgs> onCancel = (sender, args) =>
|
||||
{
|
||||
if (RequestedWritableRequirements == WritableRequirements.WriteDemanded)
|
||||
ReturnCancel();
|
||||
else
|
||||
ReturnOk(ioc);
|
||||
};
|
||||
ShowAlertDialog(readOnlyExplanation + " "
|
||||
+ (RequestedWritableRequirements == WritableRequirements.WriteDemanded ?
|
||||
_app.GetResourceString(UiStringKey.CopyFileRequired)
|
||||
: _app.GetResourceString(UiStringKey.CopyFileRequiredForEditing))
|
||||
+ " "
|
||||
+ _app.GetResourceString(UiStringKey.ClickOkToSelectLocation), onOk, onCancel);
|
||||
return;
|
||||
}
|
||||
ReturnOk(ioc);
|
||||
}
|
||||
|
||||
protected abstract void ShowAlertDialog(string message, EventHandler<DialogClickEventArgs> onOk, EventHandler<DialogClickEventArgs> onCancel);
|
||||
|
||||
protected abstract WritableRequirements RequestedWritableRequirements { get; }
|
||||
|
||||
protected abstract void ReturnOk(IOConnectionInfo ioc);
|
||||
|
||||
protected abstract void ReturnCancel();
|
||||
}
|
||||
}
|
@ -48,6 +48,12 @@ namespace keepass2android
|
||||
SynchronizingOtpAuxFile,
|
||||
SavingOtpAuxFile,
|
||||
CertificateFailure,
|
||||
exporting_database
|
||||
exporting_database,
|
||||
FileIsTemporarilyAvailable,
|
||||
CopyFileRequired,
|
||||
ClickOkToSelectLocation,
|
||||
FileIsReadOnly,
|
||||
FileIsReadOnlyOnKitkat,
|
||||
CopyFileRequiredForEditing
|
||||
}
|
||||
}
|
@ -119,7 +119,7 @@ namespace keepass2android
|
||||
KpDatabase = pwDatabase;
|
||||
SearchHelper = new SearchDbHelper(app);
|
||||
|
||||
CanWrite = databaseLoader.CanWrite;
|
||||
CanWrite = databaseLoader.CanWrite && !fileStorage.IsReadOnly(iocInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -84,6 +84,7 @@
|
||||
<Compile Include="TestCachingFileStorage.cs" />
|
||||
<Compile Include="TestSaveDb.cs" />
|
||||
<Compile Include="TestSaveDbCached.cs" />
|
||||
<Compile Include="TestSelectStorageLocation.cs" />
|
||||
<Compile Include="TestSynchronizeCachedDatabase.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -23,7 +23,7 @@ namespace Kp2aUnitTests
|
||||
//runner.AddTests(typeof(TestLoadDb).GetMethod("TestLoadKdb1WithKeyfileOnly"));
|
||||
|
||||
|
||||
runner.AddTests(new List<Type> { typeof(TestBuiltInFileStorage) });
|
||||
runner.AddTests(new List<Type> { typeof(TestSelectStorageLocation) });
|
||||
//runner.AddTests(new List<Type> { typeof(TestSynchronizeCachedDatabase)});
|
||||
//runner.AddTests(typeof(TestLoadDb).GetMethod("LoadErrorWithCertificateTrustFailure"));
|
||||
//runner.AddTests(typeof(TestLoadDb).GetMethod("LoadWithAcceptedCertificateTrustFailure"));
|
||||
|
33
src/Kp2aUnitTests/TestAndroidContentFileStorage.cs
Normal file
33
src/Kp2aUnitTests/TestAndroidContentFileStorage.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Java.IO;
|
||||
using KeePassLib;
|
||||
using KeePassLib.Interfaces;
|
||||
using KeePassLib.Keys;
|
||||
using KeePassLib.Serialization;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using keepass2android;
|
||||
using keepass2android.Io;
|
||||
|
||||
namespace Kp2aUnitTests
|
||||
{
|
||||
[TestClass]
|
||||
internal class TestBuiltInFileStorage
|
||||
{
|
||||
[TestMethod]
|
||||
public void ReadOnlyKitKat()
|
||||
{
|
||||
var storage = new BuiltInFileStorage(new TestKp2aApp());
|
||||
var extFile = "/storage/sdcard1/file.txt";
|
||||
Assert.IsTrue(storage.IsReadOnly(IOConnectionInfo.FromPath(extFile)));
|
||||
Assert.IsTrue(storage.IsReadOnly(IOConnectionInfo.FromPath(extFile)));
|
||||
|
||||
Assert.IsFalse(storage.IsReadOnly(IOConnectionInfo.FromPath(Application.Context.GetExternalFilesDir(null).AbsolutePath+ "/file.txt")));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -134,11 +134,18 @@ namespace Kp2aUnitTests
|
||||
return new ProgressDialogStub();
|
||||
}
|
||||
|
||||
public IFileStorage GetFileStorage(IOConnectionInfo iocInfo)
|
||||
public virtual IFileStorage GetFileStorage(IOConnectionInfo iocInfo)
|
||||
{
|
||||
return FileStorage;
|
||||
}
|
||||
|
||||
public virtual IFileStorage GetFileStorage(IOConnectionInfo iocInfo, bool allowCache)
|
||||
{
|
||||
if (FileStorage is CachingFileStorage)
|
||||
throw new Exception("bad test class");
|
||||
return FileStorage;
|
||||
}
|
||||
|
||||
|
||||
public bool TriggerReloadCalled;
|
||||
private TestFileStorage _testFileStorage;
|
||||
|
790
src/Kp2aUnitTests/TestSelectStorageLocation.cs
Normal file
790
src/Kp2aUnitTests/TestSelectStorageLocation.cs
Normal file
@ -0,0 +1,790 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using KeePassLib.Serialization;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using keepass2android;
|
||||
using keepass2android.Io;
|
||||
|
||||
namespace Kp2aUnitTests
|
||||
{
|
||||
|
||||
class TemporaryFileStorage: IFileStorage
|
||||
{
|
||||
public IEnumerable<string> SupportedProtocols
|
||||
{
|
||||
get {
|
||||
yield return "content";
|
||||
yield return "readonly";
|
||||
}
|
||||
}
|
||||
|
||||
public void Delete(IOConnectionInfo ioc)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public string GetCurrentFileVersionFast(IOConnectionInfo ioc)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public Stream OpenFileForRead(IOConnectionInfo ioc)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool RequiresCredentials(IOConnectionInfo ioc)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void CreateDirectory(IOConnectionInfo ioc, string newDirName)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IEnumerable<FileDescription> ListContents(IOConnectionInfo ioc)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public FileDescription GetFileDescription(IOConnectionInfo ioc)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool RequiresSetup(IOConnectionInfo ioConnection)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public string IocToPath(IOConnectionInfo ioc)
|
||||
{
|
||||
return ioc.Path;
|
||||
}
|
||||
|
||||
public void StartSelectFile(IFileStorageSetupInitiatorActivity activity, bool isForSave, int requestCode, string protocolId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode,
|
||||
bool alwaysReturnSuccess)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnCreate(IFileStorageSetupActivity activity, Bundle savedInstanceState)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnResume(IFileStorageSetupActivity activity)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string CreateFilePath(string parent, string newFilename)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IOConnectionInfo GetParentPath(IOConnectionInfo ioc)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IOConnectionInfo GetFilePath(IOConnectionInfo folderPath, string filename)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsPermanentLocation(IOConnectionInfo ioc)
|
||||
{
|
||||
return ioc.Path.StartsWith("content") == false;
|
||||
}
|
||||
|
||||
public bool IsReadOnly(IOConnectionInfo ioc)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class TestKp2aAppForSelectStorageLocation: TestKp2aApp
|
||||
{
|
||||
|
||||
|
||||
public override IFileStorage GetFileStorage(IOConnectionInfo iocInfo, bool allowCache)
|
||||
{
|
||||
if ((iocInfo.Path.StartsWith("content://")) || (iocInfo.Path.StartsWith("readonly://")))
|
||||
{
|
||||
return new TemporaryFileStorage();
|
||||
}
|
||||
return base.GetFileStorage(iocInfo);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class TestControllableSelectStorageLocationActivity: SelectStorageLocationActivityBase
|
||||
{
|
||||
|
||||
public List<string> toasts = new List<string>();
|
||||
public WritableRequirements requestedWritableRequirements;
|
||||
public bool? _result;
|
||||
public IOConnectionInfo _resultIoc;
|
||||
public object _userAction;
|
||||
private IKp2aApp _app;
|
||||
|
||||
public TestControllableSelectStorageLocationActivity(IKp2aApp app) : base(app)
|
||||
{
|
||||
_app = app;
|
||||
StartFileStorageSelection(RequestCodeFileStorageSelectionForPrimarySelect, true, false);
|
||||
}
|
||||
|
||||
protected override void ShowToast(string text)
|
||||
{
|
||||
toasts.Add(text);
|
||||
}
|
||||
|
||||
protected override void CopyFile(IOConnectionInfo targetIoc, IOConnectionInfo sourceIoc)
|
||||
{
|
||||
if (CopyFileShouldFail)
|
||||
{
|
||||
throw new Exception("CopyFile failed in test.");
|
||||
}
|
||||
}
|
||||
|
||||
public bool CopyFileShouldFail { get; set; }
|
||||
|
||||
protected override void ShowInvalidSchemeMessage(string dataString)
|
||||
{
|
||||
toasts.Add("invalid scheme: " + dataString);
|
||||
}
|
||||
|
||||
protected override string IntentToFilename(Intent data)
|
||||
{
|
||||
return data.GetStringExtra("path");
|
||||
}
|
||||
|
||||
protected override void SetIoConnectionFromIntent(IOConnectionInfo ioc, Intent data)
|
||||
{
|
||||
ioc.Path = data.GetStringExtra("path");
|
||||
}
|
||||
|
||||
protected override Result ExitFileStorageSelectionOk
|
||||
{
|
||||
get { return Result.FirstUser + 825; }
|
||||
}
|
||||
|
||||
protected override void StartSelectFile(bool isForSave, int browseRequestCode, string protocolId)
|
||||
{
|
||||
_userAction = new SelectFileAction(isForSave, browseRequestCode, protocolId, this);
|
||||
}
|
||||
|
||||
public void HandleActivityResult(int requestCode, Result resultCode, Intent data)
|
||||
{
|
||||
OnActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
internal class SelectFileAction
|
||||
{
|
||||
private readonly bool _isForSave;
|
||||
private readonly int _browseRequestCode;
|
||||
private readonly string _protocolId;
|
||||
private readonly TestControllableSelectStorageLocationActivity _testControllableSelectStorageLocationActivity;
|
||||
|
||||
public SelectFileAction(bool isForSave, int browseRequestCode, string protocolId, TestControllableSelectStorageLocationActivity testControllableSelectStorageLocationActivity)
|
||||
{
|
||||
_isForSave = isForSave;
|
||||
_browseRequestCode = browseRequestCode;
|
||||
_protocolId = protocolId;
|
||||
_testControllableSelectStorageLocationActivity = testControllableSelectStorageLocationActivity;
|
||||
}
|
||||
|
||||
public bool IsForSave {
|
||||
get { return _isForSave; }
|
||||
}
|
||||
|
||||
public int BrowseRequestCode
|
||||
{
|
||||
get { return _browseRequestCode; }
|
||||
}
|
||||
|
||||
public string ProtocolId
|
||||
{
|
||||
get { return _protocolId; }
|
||||
}
|
||||
|
||||
|
||||
public void PerformManualFileSelect(string path)
|
||||
{
|
||||
_testControllableSelectStorageLocationActivity.PressOpenButton(path, _browseRequestCode);
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
_testControllableSelectStorageLocationActivity.ReturnCancel();
|
||||
}
|
||||
|
||||
public void PrepareFileChooser(string protocolId)
|
||||
{
|
||||
Intent data = new Intent();
|
||||
data.PutExtra("path", protocolId+"://");
|
||||
_testControllableSelectStorageLocationActivity.HandleActivityResult(_browseRequestCode, (Result) FileStorageResults.FileChooserPrepared, data);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void PressOpenButton(string path, int browseRequestCode)
|
||||
{
|
||||
OnOpenButton(path, browseRequestCode);
|
||||
}
|
||||
|
||||
|
||||
internal class FileStorageSelectionAction
|
||||
{
|
||||
private readonly int _requestCode;
|
||||
private readonly bool _allowThirdPartyGet;
|
||||
private readonly bool _allowThirdPartySend;
|
||||
private readonly TestControllableSelectStorageLocationActivity _testControllableSelectStorageLocationActivity;
|
||||
|
||||
public FileStorageSelectionAction(int requestCode, bool allowThirdPartyGet, bool allowThirdPartySend, TestControllableSelectStorageLocationActivity testControllableSelectStorageLocationActivity)
|
||||
{
|
||||
_requestCode = requestCode;
|
||||
_allowThirdPartyGet = allowThirdPartyGet;
|
||||
_allowThirdPartySend = allowThirdPartySend;
|
||||
_testControllableSelectStorageLocationActivity = testControllableSelectStorageLocationActivity;
|
||||
}
|
||||
|
||||
public int RequestCode
|
||||
{
|
||||
get { return _requestCode; }
|
||||
}
|
||||
|
||||
public bool AllowThirdPartyGet
|
||||
{
|
||||
get { return _allowThirdPartyGet; }
|
||||
}
|
||||
|
||||
public bool AllowThirdPartySend
|
||||
{
|
||||
get { return _allowThirdPartySend; }
|
||||
}
|
||||
|
||||
public void ReturnProtocol(string protocolId)
|
||||
{
|
||||
Intent intent = new Intent();
|
||||
intent.PutExtra("protocolId", protocolId);
|
||||
_testControllableSelectStorageLocationActivity.HandleActivityResult(_requestCode, Result.FirstUser + 825 /*fs select ok*/, intent);
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
_testControllableSelectStorageLocationActivity.HandleActivityResult(_requestCode, Result.Canceled, null);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ShowAndroidBrowseDialog(int requestCode, bool isForSave)
|
||||
{
|
||||
_userAction = new AndroidBrowseDialogAction(requestCode, isForSave, this);
|
||||
}
|
||||
|
||||
internal class AndroidBrowseDialogAction
|
||||
{
|
||||
private readonly int _requestCode;
|
||||
private readonly bool _isForSave;
|
||||
private readonly TestControllableSelectStorageLocationActivity _activity;
|
||||
|
||||
public AndroidBrowseDialogAction(int requestCode, bool isForSave, TestControllableSelectStorageLocationActivity activity)
|
||||
{
|
||||
_requestCode = requestCode;
|
||||
_isForSave = isForSave;
|
||||
_activity = activity;
|
||||
}
|
||||
|
||||
public int RequestCode
|
||||
{
|
||||
get { return _requestCode; }
|
||||
}
|
||||
|
||||
public void ReturnSelectedFile(string selectedUri)
|
||||
{
|
||||
Intent data = new Intent();
|
||||
data.PutExtra("path", selectedUri);
|
||||
_activity.HandleActivityResult(_requestCode, Result.Ok, data);
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
_activity.HandleActivityResult(_requestCode, Result.Canceled, null);
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool IsStorageSelectionForSave { get { return SelectLocationForSave; } }
|
||||
|
||||
private bool SelectLocationForSave { get; set; }
|
||||
|
||||
protected override void PerformCopy(Func<Action> copyAndReturnPostExecute)
|
||||
{
|
||||
Action postExec = copyAndReturnPostExecute();
|
||||
postExec();
|
||||
}
|
||||
|
||||
protected override void StartFileStorageSelection(int requestCode, bool allowThirdPartyGet, bool allowThirdPartySend)
|
||||
{
|
||||
_userAction = new FileStorageSelectionAction(requestCode, allowThirdPartyGet, allowThirdPartySend, this);
|
||||
}
|
||||
|
||||
protected override void StartFileChooser(string path, int requestCode, bool isForSave)
|
||||
{
|
||||
_userAction = new FileChooserAction(path, requestCode, isForSave, this);
|
||||
}
|
||||
|
||||
internal class FileChooserAction
|
||||
{
|
||||
private readonly string _path;
|
||||
private readonly int _requestCode;
|
||||
private readonly bool _isForSave;
|
||||
private readonly TestControllableSelectStorageLocationActivity _activity;
|
||||
|
||||
public FileChooserAction(string path, int requestCode, bool isForSave, TestControllableSelectStorageLocationActivity activity)
|
||||
{
|
||||
_path = path;
|
||||
_requestCode = requestCode;
|
||||
_isForSave = isForSave;
|
||||
_activity = activity;
|
||||
}
|
||||
|
||||
public string Path
|
||||
{
|
||||
get { return _path; }
|
||||
}
|
||||
|
||||
public int RequestCode
|
||||
{
|
||||
get { return _requestCode; }
|
||||
}
|
||||
|
||||
public bool IsForSave
|
||||
{
|
||||
get { return _isForSave; }
|
||||
}
|
||||
|
||||
public void ReturnChosenFile(string path)
|
||||
{
|
||||
Intent data = new Intent();
|
||||
data.PutExtra("path", path);
|
||||
_activity.HandleActivityResult(_requestCode, Result.Ok, data);
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
_activity.HandleActivityResult(_requestCode, Result.Canceled, null);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ShowAlertDialog(string message, EventHandler<DialogClickEventArgs> onOk, EventHandler<DialogClickEventArgs> onCancel)
|
||||
{
|
||||
_userAction = new ShowAlertDialogAction(message, onOk, onCancel);
|
||||
}
|
||||
|
||||
internal class ShowAlertDialogAction
|
||||
{
|
||||
public string Message { get; set; }
|
||||
public EventHandler<DialogClickEventArgs> OnOk { get; set; }
|
||||
public EventHandler<DialogClickEventArgs> OnCancel { get; set; }
|
||||
|
||||
public ShowAlertDialogAction(string message, EventHandler<DialogClickEventArgs> onOk, EventHandler<DialogClickEventArgs> onCancel)
|
||||
{
|
||||
Message = message;
|
||||
OnOk = onOk;
|
||||
OnCancel = onCancel;
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
OnCancel(this, null);
|
||||
}
|
||||
|
||||
public void Ok()
|
||||
{
|
||||
OnOk(this, null);
|
||||
}
|
||||
}
|
||||
|
||||
protected override WritableRequirements RequestedWritableRequirements
|
||||
{
|
||||
get { return requestedWritableRequirements; }
|
||||
}
|
||||
|
||||
public IKp2aApp App
|
||||
{
|
||||
get { return _app; }
|
||||
}
|
||||
|
||||
protected override void ReturnOk(IOConnectionInfo ioc)
|
||||
{
|
||||
_result = true;
|
||||
_resultIoc = ioc;
|
||||
}
|
||||
|
||||
protected override void ReturnCancel()
|
||||
{
|
||||
_result = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[TestClass]
|
||||
class TestSelectStorageLocation
|
||||
{
|
||||
[TestInitialize]
|
||||
public void Init()
|
||||
{
|
||||
try
|
||||
{
|
||||
Looper.Prepare();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestCancelFileStorageSelection()
|
||||
{
|
||||
var testee = CreateTestee();
|
||||
var action = (TestControllableSelectStorageLocationActivity.FileStorageSelectionAction)testee._userAction;
|
||||
action.Cancel();
|
||||
Assert.IsFalse((bool) testee._result);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestSimpleManualSelect()
|
||||
{
|
||||
var testee = CreateTestee();
|
||||
var action = (TestControllableSelectStorageLocationActivity.FileStorageSelectionAction) testee._userAction;
|
||||
action.ReturnProtocol("ftp");
|
||||
|
||||
Assert.IsNull(testee._result); //no result yet
|
||||
|
||||
var action2 = (TestControllableSelectStorageLocationActivity.SelectFileAction)testee._userAction;
|
||||
string path = "ftp://crocoll.net/test.kdbx";
|
||||
action2.PerformManualFileSelect(path);
|
||||
|
||||
Assert.IsTrue((bool) testee._result);
|
||||
Assert.AreEqual(testee._resultIoc.Path, path);
|
||||
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestCancelManualSelect()
|
||||
{
|
||||
var testee = CreateTestee();
|
||||
var action = (TestControllableSelectStorageLocationActivity.FileStorageSelectionAction)testee._userAction;
|
||||
action.ReturnProtocol("ftp");
|
||||
|
||||
Assert.IsNull(testee._result); //no result yet
|
||||
|
||||
var action2 = (TestControllableSelectStorageLocationActivity.SelectFileAction)testee._userAction;
|
||||
action2.Cancel();
|
||||
|
||||
Assert.IsFalse((bool)testee._result);
|
||||
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void TestCancelAndroidBrowseDialog()
|
||||
{
|
||||
var testee = CreateTestee();
|
||||
var action = (TestControllableSelectStorageLocationActivity.FileStorageSelectionAction)testee._userAction;
|
||||
action.ReturnProtocol("androidget");
|
||||
|
||||
Assert.IsNull(testee._result); //no result yet
|
||||
|
||||
var action2 = (TestControllableSelectStorageLocationActivity.AndroidBrowseDialogAction)testee._userAction;
|
||||
action2.Cancel();
|
||||
|
||||
Assert.IsFalse((bool)testee._result);
|
||||
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void TestCancelCopyTemporaryLocation()
|
||||
{
|
||||
var testee = CreateTestee();
|
||||
var action = (TestControllableSelectStorageLocationActivity.FileStorageSelectionAction)testee._userAction;
|
||||
action.ReturnProtocol("androidget");
|
||||
|
||||
var action2 = (TestControllableSelectStorageLocationActivity.AndroidBrowseDialogAction)testee._userAction;
|
||||
action2.ReturnSelectedFile("content://abc.kdbx");
|
||||
|
||||
var action3 = (TestControllableSelectStorageLocationActivity.ShowAlertDialogAction)testee._userAction;
|
||||
Assert.IsTrue(action3.Message.StartsWith(testee.App.GetResourceString(UiStringKey.FileIsTemporarilyAvailable)));
|
||||
Assert.IsNull(testee._result); //no result yet
|
||||
action3.Cancel();
|
||||
|
||||
Assert.IsFalse((bool)testee._result);
|
||||
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestCopyTemporaryLocation()
|
||||
{
|
||||
var testee = CreateTestee();
|
||||
var action = (TestControllableSelectStorageLocationActivity.FileStorageSelectionAction)testee._userAction;
|
||||
action.ReturnProtocol("androidget");
|
||||
|
||||
var action2 = (TestControllableSelectStorageLocationActivity.AndroidBrowseDialogAction)testee._userAction;
|
||||
action2.ReturnSelectedFile("content://abc.kdbx");
|
||||
|
||||
var action3 = (TestControllableSelectStorageLocationActivity.ShowAlertDialogAction)testee._userAction;
|
||||
Assert.IsTrue(action3.Message.StartsWith(testee.App.GetResourceString(UiStringKey.FileIsTemporarilyAvailable)));
|
||||
Assert.IsNull(testee._result); //no result yet
|
||||
action3.Ok();
|
||||
|
||||
|
||||
var action4 = (TestControllableSelectStorageLocationActivity.FileStorageSelectionAction)testee._userAction;
|
||||
action4.ReturnProtocol("ftp");
|
||||
|
||||
Assert.IsNull(testee._result);
|
||||
|
||||
var action5 = (TestControllableSelectStorageLocationActivity.SelectFileAction)testee._userAction;
|
||||
Assert.IsTrue(action5.IsForSave);
|
||||
string path = "ftp://crocoll.net/testtarget.kdbx";
|
||||
action5.PerformManualFileSelect(path);
|
||||
|
||||
Assert.IsTrue((bool)testee._result);
|
||||
Assert.AreEqual(path, testee._resultIoc.Path);
|
||||
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void TestCopyTemporaryLocationWithFileBrowser()
|
||||
{
|
||||
var testee = CreateTestee();
|
||||
var action = (TestControllableSelectStorageLocationActivity.FileStorageSelectionAction)testee._userAction;
|
||||
action.ReturnProtocol("androidget");
|
||||
|
||||
var action2 = (TestControllableSelectStorageLocationActivity.AndroidBrowseDialogAction)testee._userAction;
|
||||
action2.ReturnSelectedFile("content://abc.kdbx");
|
||||
|
||||
var action3 = (TestControllableSelectStorageLocationActivity.ShowAlertDialogAction)testee._userAction;
|
||||
Assert.IsTrue(action3.Message.StartsWith(testee.App.GetResourceString(UiStringKey.FileIsTemporarilyAvailable)));
|
||||
Assert.IsNull(testee._result); //no result yet
|
||||
action3.Ok();
|
||||
|
||||
|
||||
var action4 = (TestControllableSelectStorageLocationActivity.FileStorageSelectionAction)testee._userAction;
|
||||
action4.ReturnProtocol("file");
|
||||
|
||||
|
||||
var action5 = (TestControllableSelectStorageLocationActivity.SelectFileAction)testee._userAction;
|
||||
Assert.IsTrue(action5.IsForSave);
|
||||
|
||||
action5.PrepareFileChooser("file");
|
||||
|
||||
Assert.IsNull(testee._result);
|
||||
|
||||
|
||||
var action6 = (TestControllableSelectStorageLocationActivity.FileChooserAction)testee._userAction;
|
||||
Assert.IsTrue(action5.IsForSave);
|
||||
string path = "file:///mnt/sdcard/testtarget.kdbx";
|
||||
|
||||
action6.ReturnChosenFile(path);
|
||||
|
||||
string expectedpath = "/mnt/sdcard/testtarget.kdbx";
|
||||
Assert.IsTrue((bool)testee._result);
|
||||
Assert.AreEqual(expectedpath, testee._resultIoc.Path);
|
||||
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void TestCopyTemporaryLocationWithCancelFileBrowser()
|
||||
{
|
||||
var testee = CreateTestee();
|
||||
var action = (TestControllableSelectStorageLocationActivity.FileStorageSelectionAction)testee._userAction;
|
||||
action.ReturnProtocol("androidget");
|
||||
|
||||
var action2 = (TestControllableSelectStorageLocationActivity.AndroidBrowseDialogAction)testee._userAction;
|
||||
action2.ReturnSelectedFile("content://abc.kdbx");
|
||||
|
||||
var action3 = (TestControllableSelectStorageLocationActivity.ShowAlertDialogAction)testee._userAction;
|
||||
Assert.IsTrue(action3.Message.StartsWith(testee.App.GetResourceString(UiStringKey.FileIsTemporarilyAvailable)));
|
||||
Assert.IsNull(testee._result); //no result yet
|
||||
action3.Ok();
|
||||
|
||||
|
||||
var action4 = (TestControllableSelectStorageLocationActivity.FileStorageSelectionAction)testee._userAction;
|
||||
action4.ReturnProtocol("file");
|
||||
|
||||
|
||||
var action5 = (TestControllableSelectStorageLocationActivity.SelectFileAction)testee._userAction;
|
||||
Assert.IsTrue(action5.IsForSave);
|
||||
|
||||
action5.PrepareFileChooser("file");
|
||||
|
||||
Assert.IsNull(testee._result);
|
||||
|
||||
|
||||
var action6 = (TestControllableSelectStorageLocationActivity.FileChooserAction)testee._userAction;
|
||||
Assert.IsTrue(action5.IsForSave);
|
||||
string path = "file:///mnt/sdcard/testtarget.kdbx";
|
||||
|
||||
action6.Cancel();
|
||||
|
||||
Assert.IsFalse((bool)testee._result);
|
||||
|
||||
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestCancelCopyReadOnlyLocation()
|
||||
{
|
||||
SelectStorageLocationActivityBase.WritableRequirements requestedWritableRequirements = SelectStorageLocationActivityBase.WritableRequirements.WriteDesired;
|
||||
string path;
|
||||
var testee = PrepareTesteeForCancelCopyReadOnly(requestedWritableRequirements, out path);
|
||||
|
||||
Assert.IsTrue((bool)testee._result);
|
||||
Assert.AreEqual(path, testee._resultIoc.Path);
|
||||
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestCancelCopyReadOnlyLocationWriteRequired()
|
||||
{
|
||||
SelectStorageLocationActivityBase.WritableRequirements requestedWritableRequirements = SelectStorageLocationActivityBase.WritableRequirements.WriteDemanded;
|
||||
string path;
|
||||
var testee = PrepareTesteeForCancelCopyReadOnly(requestedWritableRequirements, out path);
|
||||
|
||||
Assert.IsFalse((bool)testee._result);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static TestControllableSelectStorageLocationActivity PrepareTesteeForCancelCopyReadOnly(
|
||||
SelectStorageLocationActivityBase.WritableRequirements requestedWritableRequirements, out string path)
|
||||
{
|
||||
var testee = CreateTestee();
|
||||
|
||||
testee.requestedWritableRequirements = requestedWritableRequirements;
|
||||
var action = (TestControllableSelectStorageLocationActivity.FileStorageSelectionAction) testee._userAction;
|
||||
action.ReturnProtocol("androidget");
|
||||
|
||||
var action2 = (TestControllableSelectStorageLocationActivity.AndroidBrowseDialogAction) testee._userAction;
|
||||
path = "readonly://abc.kdbx";
|
||||
action2.ReturnSelectedFile(path);
|
||||
|
||||
var action3 = (TestControllableSelectStorageLocationActivity.ShowAlertDialogAction) testee._userAction;
|
||||
Assert.IsTrue(action3.Message.StartsWith(testee.App.GetResourceString(UiStringKey.FileIsReadOnly)));
|
||||
Assert.IsNull(testee._result); //no result yet
|
||||
action3.Cancel();
|
||||
return testee;
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestOpenReadOnly()
|
||||
{
|
||||
var testee = CreateTestee();
|
||||
|
||||
testee.requestedWritableRequirements = SelectStorageLocationActivityBase.WritableRequirements.ReadOnly;
|
||||
var action = (TestControllableSelectStorageLocationActivity.FileStorageSelectionAction) testee._userAction;
|
||||
action.ReturnProtocol("androidget");
|
||||
|
||||
var action2 = (TestControllableSelectStorageLocationActivity.AndroidBrowseDialogAction) testee._userAction;
|
||||
var path = "readonly://abc.kdbx";
|
||||
action2.ReturnSelectedFile(path);
|
||||
|
||||
Assert.IsTrue((bool)testee._result);
|
||||
Assert.AreEqual(path, testee._resultIoc.Path);
|
||||
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestCopyTemporaryLocationFails()
|
||||
{
|
||||
var testee = CreateTestee();
|
||||
var action = (TestControllableSelectStorageLocationActivity.FileStorageSelectionAction)testee._userAction;
|
||||
action.ReturnProtocol("androidget");
|
||||
|
||||
var action2 = (TestControllableSelectStorageLocationActivity.AndroidBrowseDialogAction)testee._userAction;
|
||||
action2.ReturnSelectedFile("content://abc.kdbx");
|
||||
|
||||
var action3 = (TestControllableSelectStorageLocationActivity.ShowAlertDialogAction)testee._userAction;
|
||||
Assert.IsTrue(action3.Message.StartsWith(testee.App.GetResourceString(UiStringKey.FileIsTemporarilyAvailable)));
|
||||
Assert.IsNull(testee._result); //no result yet
|
||||
action3.Ok();
|
||||
|
||||
|
||||
var action4 = (TestControllableSelectStorageLocationActivity.FileStorageSelectionAction)testee._userAction;
|
||||
action4.ReturnProtocol("ftp");
|
||||
|
||||
Assert.IsNull(testee._result);
|
||||
|
||||
var action5 = (TestControllableSelectStorageLocationActivity.SelectFileAction)testee._userAction;
|
||||
Assert.IsTrue(action5.IsForSave);
|
||||
string path = "ftp://crocoll.net/testtarget.kdbx";
|
||||
|
||||
testee.CopyFileShouldFail = true;
|
||||
|
||||
action5.PerformManualFileSelect(path);
|
||||
|
||||
Assert.IsFalse((bool)testee._result);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static TestControllableSelectStorageLocationActivity CreateTestee()
|
||||
{
|
||||
return new TestControllableSelectStorageLocationActivity(new TestKp2aAppForSelectStorageLocation());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,42 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
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 KeePassLib.Utility;
|
||||
using keepass2android.Io;
|
||||
using Environment = Android.OS.Environment;
|
||||
using keepass2android.Utils;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
[Activity(Label = "")]
|
||||
public class SelectStorageLocationActivity : Activity, IDialogInterfaceOnDismissListener
|
||||
public class SelectStorageLocationActivity : SelectStorageLocationActivityBase, IDialogInterfaceOnDismissListener
|
||||
{
|
||||
private ActivityDesign _design;
|
||||
private bool _isRecreated;
|
||||
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
|
||||
}
|
||||
private const string BundleKeySelectedIoc = "BundleKeySelectedIoc";
|
||||
|
||||
|
||||
public const string ExtraKeyWritableRequirements = "EXTRA_KEY_WRITABLE_REQUIREMENTS";
|
||||
|
||||
public SelectStorageLocationActivity()
|
||||
public SelectStorageLocationActivity() : base(App.Kp2a)
|
||||
{
|
||||
_design = new ActivityDesign(this);
|
||||
}
|
||||
@ -58,6 +42,8 @@ namespace keepass2android
|
||||
|
||||
bool allowThirdPartyGet = Intent.GetBooleanExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, false);
|
||||
bool allowThirdPartySend = Intent.GetBooleanExtra(FileStorageSelectionActivity.AllowThirdPartyAppSend, false);
|
||||
|
||||
bool isRecreated = false;
|
||||
if (bundle == null)
|
||||
State = new Bundle();
|
||||
else
|
||||
@ -66,15 +52,14 @@ namespace keepass2android
|
||||
var selectedIocString = bundle.GetString(BundleKeySelectedIoc, null);
|
||||
if (selectedIocString != null)
|
||||
_selectedIoc = IOConnectionInfo.UnserializeFromString(selectedIocString);
|
||||
_isRecreated = true;
|
||||
isRecreated = true;
|
||||
}
|
||||
|
||||
if (!_isRecreated)
|
||||
//todo: handle orientation change while dialog is shown
|
||||
|
||||
if (!isRecreated)
|
||||
{
|
||||
Intent intent = new Intent(this, typeof(FileStorageSelectionActivity));
|
||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, allowThirdPartyGet);
|
||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppSend, allowThirdPartySend);
|
||||
StartActivityForResult(intent, RequestCodeFileStorageSelectionForPrimarySelect);
|
||||
StartFileStorageSelection(RequestCodeFileStorageSelectionForPrimarySelect, allowThirdPartyGet, allowThirdPartySend);
|
||||
}
|
||||
|
||||
|
||||
@ -82,7 +67,58 @@ namespace keepass2android
|
||||
|
||||
protected Bundle State { get; set; }
|
||||
|
||||
protected bool IsStorageSelectionForSave
|
||||
protected override void ShowToast(string text)
|
||||
{
|
||||
Toast.MakeText(this, text, ToastLength.Long).Show();
|
||||
}
|
||||
|
||||
protected override void ShowInvalidSchemeMessage(string dataString)
|
||||
{
|
||||
Toast.MakeText(this, Resources.GetString(Resource.String.unknown_uri_scheme, new Java.Lang.Object[] { dataString }),
|
||||
ToastLength.Long).Show();
|
||||
}
|
||||
|
||||
protected override string IntentToFilename(Intent data)
|
||||
{
|
||||
return Util.IntentToFilename(data, this);
|
||||
}
|
||||
|
||||
protected override void SetIoConnectionFromIntent(IOConnectionInfo ioc, Intent data)
|
||||
{
|
||||
PasswordActivity.SetIoConnectionFromIntent(ioc, data);
|
||||
}
|
||||
|
||||
protected override Result ExitFileStorageSelectionOk
|
||||
{
|
||||
get { return KeePass.ExitFileStorageSelectionOk; }
|
||||
}
|
||||
|
||||
protected override void StartSelectFile( bool isForSave, int browseRequestCode, string protocolId)
|
||||
{
|
||||
var startManualFileSelect = new Action<string>(defaultPath =>
|
||||
{
|
||||
if (defaultPath.StartsWith("sftp://"))
|
||||
Util.ShowSftpDialog(this, filename => OnReceivedSftpData(filename, browseRequestCode, isForSave), ReturnCancel);
|
||||
else
|
||||
//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);
|
||||
});
|
||||
;
|
||||
App.Kp2a.GetFileStorage(protocolId).StartSelectFile(new FileStorageSetupInitiatorActivity(this,
|
||||
OnActivityResult,
|
||||
startManualFileSelect
|
||||
), isForSave, browseRequestCode, protocolId);
|
||||
}
|
||||
|
||||
protected override void ShowAndroidBrowseDialog(int requestCode, bool isForSave)
|
||||
{
|
||||
Util.ShowBrowseDialog(this, requestCode, isForSave);
|
||||
}
|
||||
|
||||
protected override bool IsStorageSelectionForSave
|
||||
{
|
||||
get { return Intent.GetBooleanExtra(FileStorageSetupDefs.ExtraIsForSave, false); }
|
||||
}
|
||||
@ -103,241 +139,14 @@ namespace keepass2android
|
||||
_design.ReapplyTheme();
|
||||
}
|
||||
|
||||
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
|
||||
{
|
||||
base.OnActivityResult(requestCode, resultCode, data);
|
||||
if ((requestCode == RequestCodeFileStorageSelectionForPrimarySelect) || ((requestCode == RequestCodeFileStorageSelectionForCopyToWritableLocation)))
|
||||
{
|
||||
int browseRequestCode = Intents.RequestCodeFileBrowseForOpen;
|
||||
if (requestCode == RequestCodeFileStorageSelectionForCopyToWritableLocation)
|
||||
{
|
||||
browseRequestCode = RequestCodeFileFileBrowseForWritableLocation;
|
||||
}
|
||||
|
||||
if (resultCode == KeePass.ExitFileStorageSelectionOk)
|
||||
{
|
||||
|
||||
string protocolId = data.GetStringExtra("protocolId");
|
||||
|
||||
if (protocolId == "androidget")
|
||||
{
|
||||
Util.ShowBrowseDialog(this, Intents.RequestCodeFileBrowseForOpen, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isForSave = (requestCode == RequestCodeFileStorageSelectionForPrimarySelect) ?
|
||||
IsStorageSelectionForSave : true;
|
||||
|
||||
App.Kp2a.GetFileStorage(protocolId).StartSelectFile(new FileStorageSetupInitiatorActivity(this,
|
||||
OnActivityResult,
|
||||
defaultPath =>
|
||||
{
|
||||
if (defaultPath.StartsWith("sftp://"))
|
||||
Util.ShowSftpDialog(this, filename => OnReceivedSftpData(filename, browseRequestCode, isForSave), ReturnCancel);
|
||||
else
|
||||
//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);
|
||||
}
|
||||
), isForSave, browseRequestCode, protocolId);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
ReturnCancel();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
if (filename != null)
|
||||
{
|
||||
if (filename.StartsWith("file://"))
|
||||
{
|
||||
filename = filename.Substring(7);
|
||||
filename = Java.Net.URLDecoder.Decode(filename);
|
||||
}
|
||||
|
||||
IOConnectionInfo ioc = new IOConnectionInfo
|
||||
{
|
||||
Path = filename
|
||||
};
|
||||
|
||||
IocSelected(ioc, requestCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data.Data.Scheme == "content")
|
||||
{
|
||||
IocSelected(IOConnectionInfo.FromPath(data.DataString), requestCode);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Toast.MakeText(this, Resources.GetString(Resource.String.unknown_uri_scheme, new Java.Lang.Object[] {data.DataString}),
|
||||
ToastLength.Long).Show();
|
||||
ReturnCancel();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ReturnCancel();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void ReturnCancel()
|
||||
protected override void ReturnCancel()
|
||||
{
|
||||
SetResult(Result.Canceled);
|
||||
Finish();
|
||||
}
|
||||
|
||||
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)
|
||||
protected override void ReturnOk(IOConnectionInfo ioc)
|
||||
{
|
||||
Intent intent = new Intent();
|
||||
PasswordActivity.PutIoConnectionToIntent(ioc, intent);
|
||||
@ -345,42 +154,52 @@ namespace keepass2android
|
||||
Finish();
|
||||
}
|
||||
|
||||
private WritableRequirements RequestedWritableRequirements
|
||||
protected override void ShowAlertDialog(string message, EventHandler<DialogClickEventArgs> onOk, EventHandler<DialogClickEventArgs> onCancel)
|
||||
{
|
||||
new AlertDialog.Builder(this)
|
||||
.SetPositiveButton(Android.Resource.String.Ok, onOk)
|
||||
.SetMessage(message)
|
||||
.SetCancelable(false)
|
||||
.SetNegativeButton(Android.Resource.String.Cancel, onCancel)
|
||||
.Create()
|
||||
.Show();
|
||||
|
||||
}
|
||||
|
||||
protected override WritableRequirements RequestedWritableRequirements
|
||||
{
|
||||
get { return (WritableRequirements) Intent.GetIntExtra(ExtraKeyWritableRequirements, (int)WritableRequirements.ReadOnly); }
|
||||
}
|
||||
|
||||
private void MoveToWritableLocation(IOConnectionInfo ioc)
|
||||
{
|
||||
_selectedIoc = ioc;
|
||||
|
||||
|
||||
#if !EXCLUDE_FILECHOOSER
|
||||
protected override void PerformCopy(Func<Action> copyAndReturnPostExecute)
|
||||
{
|
||||
|
||||
new SimpleLoadingDialog(this, GetString(Resource.String.CopyingFile), false,
|
||||
copyAndReturnPostExecute
|
||||
).Execute();
|
||||
}
|
||||
|
||||
protected override void StartFileStorageSelection(int requestCode, bool allowThirdPartyGet,
|
||||
bool allowThirdPartySend)
|
||||
{
|
||||
Intent intent = new Intent(this, typeof(FileStorageSelectionActivity));
|
||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, false);
|
||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppSend, false);
|
||||
|
||||
StartActivityForResult(intent, RequestCodeFileStorageSelectionForCopyToWritableLocation);
|
||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, allowThirdPartyGet);
|
||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppSend, allowThirdPartySend);
|
||||
|
||||
StartActivityForResult(intent, requestCode);
|
||||
}
|
||||
|
||||
private bool OnReceivedSftpData(string filename, int requestCode, bool isForSave)
|
||||
protected override void StartFileChooser(string defaultPath, int requestCode, bool forSave)
|
||||
{
|
||||
IOConnectionInfo ioc = new IOConnectionInfo { Path = filename };
|
||||
#if !EXCLUDE_FILECHOOSER
|
||||
StartFileChooser(ioc.Path, requestCode, isForSave);
|
||||
#else
|
||||
IocSelected(ioc, requestCode);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !EXCLUDE_FILECHOOSER
|
||||
private void StartFileChooser(string defaultPath, int requestCode, bool forSave)
|
||||
{
|
||||
Kp2aLog.Log("FSA: defaultPath="+defaultPath);
|
||||
Kp2aLog.Log("FSA: defaultPath=" + defaultPath);
|
||||
string fileProviderAuthority = FileChooserFileProvider.TheAuthority;
|
||||
if (defaultPath.StartsWith("file://"))
|
||||
{
|
||||
fileProviderAuthority = PackageName+".android-filechooser.localfile";
|
||||
fileProviderAuthority = PackageName + ".android-filechooser.localfile";
|
||||
}
|
||||
Intent i = Keepass2android.Kp2afilechooser.Kp2aFileChooserBridge.GetLaunchFileChooserIntent(this, fileProviderAuthority,
|
||||
defaultPath);
|
||||
@ -389,31 +208,26 @@ namespace keepass2android
|
||||
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");
|
||||
var ext = UrlUtil.GetExtension(defaultPath);
|
||||
if ((ext != String.Empty) && (ext.Contains("?")==false))
|
||||
i.PutExtra("group.pals.android.lib.ui.filechooser.FileChooserActivity.default_file_ext", ext);
|
||||
}
|
||||
StartActivityForResult(i, requestCode);
|
||||
|
||||
#else
|
||||
IocSelected(new IOConnectionInfo { Path = "/mnt/sdcard/keepass/yubi.kdbx" }, requestCode);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
private bool OnOpenButton(String fileName, int requestCode)
|
||||
{
|
||||
|
||||
|
||||
IOConnectionInfo ioc = new IOConnectionInfo
|
||||
{
|
||||
Path = fileName
|
||||
};
|
||||
|
||||
IocSelected(ioc, requestCode);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public void OnDismiss(IDialogInterface dialog)
|
||||
{
|
||||
// ReturnCancel();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -345,7 +345,7 @@ namespace keepass2android
|
||||
{
|
||||
string filename = ((EditText) dialog.FindViewById(Resource.Id.file_filename)).Text;
|
||||
|
||||
ShowBrowseDialog(activity, requestCodeBrowse, onCreate != null);
|
||||
Util.ShowBrowseDialog(activity, requestCodeBrowse, onCreate != null);
|
||||
|
||||
};
|
||||
|
||||
|
@ -392,6 +392,10 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
public IFileStorage GetFileStorage(IOConnectionInfo iocInfo)
|
||||
{
|
||||
return GetFileStorage(iocInfo, true);
|
||||
}
|
||||
public IFileStorage GetFileStorage(IOConnectionInfo iocInfo, bool allowCache)
|
||||
{
|
||||
if (iocInfo.IsLocalFile())
|
||||
return new BuiltInFileStorage(this);
|
||||
@ -399,9 +403,8 @@ namespace keepass2android
|
||||
{
|
||||
IFileStorage innerFileStorage = GetCloudFileStorage(iocInfo);
|
||||
|
||||
if (DatabaseCacheEnabled)
|
||||
if (DatabaseCacheEnabled && allowCache)
|
||||
{
|
||||
//TODO
|
||||
return new CachingFileStorage(innerFileStorage, Application.Context.CacheDir.Path, this);
|
||||
}
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user