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
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamplePlugin", "SamplePlugin\SamplePlugin.csproj", "{4C1BB6F8-D2CD-49C2-9053-21705681356C}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamplePlugin", "SamplePlugin\SamplePlugin.csproj", "{4C1BB6F8-D2CD-49C2-9053-21705681356C}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoTypeNeo", "..\..\..\..\..\Dropbox\programmieren\KeepassPlugins\AutoTypeNeo\AutoTypeNeo.csproj", "{4E5181A6-5FC4-4963-87B3-BAD15E7A765B}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
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|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
{4C1BB6F8-D2CD-49C2-9053-21705681356C}.ReleaseNoNet|Win32.ActiveCfg = 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
|
{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
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -474,7 +454,6 @@ Global
|
|||||||
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C} = {CAC7DBC4-E21F-41E1-B33A-E3A04585F6A3}
|
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C} = {CAC7DBC4-E21F-41E1-B33A-E3A04585F6A3}
|
||||||
{BBF77830-BC7D-4F28-A255-A348B5C6A925} = {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}
|
{4C1BB6F8-D2CD-49C2-9053-21705681356C} = {CAC7DBC4-E21F-41E1-B33A-E3A04585F6A3}
|
||||||
{4E5181A6-5FC4-4963-87B3-BAD15E7A765B} = {CAC7DBC4-E21F-41E1-B33A-E3A04585F6A3}
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(MonoDevelopProperties) = preSolution
|
GlobalSection(MonoDevelopProperties) = preSolution
|
||||||
StartupItem = keepass2android\keepass2android.csproj
|
StartupItem = keepass2android\keepass2android.csproj
|
||||||
|
@ -79,8 +79,17 @@ namespace keepass2android
|
|||||||
Handler UiThreadHandler { get; }
|
Handler UiThreadHandler { get; }
|
||||||
|
|
||||||
IProgressDialog CreateProgressDialog(Context ctx);
|
IProgressDialog CreateProgressDialog(Context ctx);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// returns the file storage for the given ioc. might be a caching file storage
|
||||||
|
/// </summary>
|
||||||
IFileStorage GetFileStorage(IOConnectionInfo iocInfo);
|
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);
|
void TriggerReload(Context context);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -90,5 +99,7 @@ namespace keepass2android
|
|||||||
//bool OnServerCertificateError(int certificateProblem);
|
//bool OnServerCertificateError(int certificateProblem);
|
||||||
|
|
||||||
RemoteCertificateValidationCallback CertificateValidationCallback { get; }
|
RemoteCertificateValidationCallback CertificateValidationCallback { get; }
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -80,6 +80,7 @@
|
|||||||
<Compile Include="Io\SkyDriveFileStorage.cs" />
|
<Compile Include="Io\SkyDriveFileStorage.cs" />
|
||||||
<Compile Include="IProgressDialog.cs" />
|
<Compile Include="IProgressDialog.cs" />
|
||||||
<Compile Include="PreferenceKey.cs" />
|
<Compile Include="PreferenceKey.cs" />
|
||||||
|
<Compile Include="SelectStorageLocationActivityBase.cs" />
|
||||||
<Compile Include="UiStringKey.cs" />
|
<Compile Include="UiStringKey.cs" />
|
||||||
<Compile Include="database\Database.cs" />
|
<Compile Include="database\Database.cs" />
|
||||||
<Compile Include="database\edit\ActionOnFinish.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,
|
SynchronizingOtpAuxFile,
|
||||||
SavingOtpAuxFile,
|
SavingOtpAuxFile,
|
||||||
CertificateFailure,
|
CertificateFailure,
|
||||||
exporting_database
|
exporting_database,
|
||||||
|
FileIsTemporarilyAvailable,
|
||||||
|
CopyFileRequired,
|
||||||
|
ClickOkToSelectLocation,
|
||||||
|
FileIsReadOnly,
|
||||||
|
FileIsReadOnlyOnKitkat,
|
||||||
|
CopyFileRequiredForEditing
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -119,7 +119,7 @@ namespace keepass2android
|
|||||||
KpDatabase = pwDatabase;
|
KpDatabase = pwDatabase;
|
||||||
SearchHelper = new SearchDbHelper(app);
|
SearchHelper = new SearchDbHelper(app);
|
||||||
|
|
||||||
CanWrite = databaseLoader.CanWrite;
|
CanWrite = databaseLoader.CanWrite && !fileStorage.IsReadOnly(iocInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -84,6 +84,7 @@
|
|||||||
<Compile Include="TestCachingFileStorage.cs" />
|
<Compile Include="TestCachingFileStorage.cs" />
|
||||||
<Compile Include="TestSaveDb.cs" />
|
<Compile Include="TestSaveDb.cs" />
|
||||||
<Compile Include="TestSaveDbCached.cs" />
|
<Compile Include="TestSaveDbCached.cs" />
|
||||||
|
<Compile Include="TestSelectStorageLocation.cs" />
|
||||||
<Compile Include="TestSynchronizeCachedDatabase.cs" />
|
<Compile Include="TestSynchronizeCachedDatabase.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -23,7 +23,7 @@ namespace Kp2aUnitTests
|
|||||||
//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(TestSelectStorageLocation) });
|
||||||
//runner.AddTests(new List<Type> { typeof(TestSynchronizeCachedDatabase)});
|
//runner.AddTests(new List<Type> { typeof(TestSynchronizeCachedDatabase)});
|
||||||
//runner.AddTests(typeof(TestLoadDb).GetMethod("LoadErrorWithCertificateTrustFailure"));
|
//runner.AddTests(typeof(TestLoadDb).GetMethod("LoadErrorWithCertificateTrustFailure"));
|
||||||
//runner.AddTests(typeof(TestLoadDb).GetMethod("LoadWithAcceptedCertificateTrustFailure"));
|
//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();
|
return new ProgressDialogStub();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IFileStorage GetFileStorage(IOConnectionInfo iocInfo)
|
public virtual IFileStorage GetFileStorage(IOConnectionInfo iocInfo)
|
||||||
{
|
{
|
||||||
return FileStorage;
|
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;
|
public bool TriggerReloadCalled;
|
||||||
private TestFileStorage _testFileStorage;
|
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;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
using Android.App;
|
using Android.App;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
using Android.OS;
|
using Android.OS;
|
||||||
using Android.Runtime;
|
|
||||||
using Android.Views;
|
|
||||||
using Android.Widget;
|
using Android.Widget;
|
||||||
using Group.Pals.Android.Lib.UI.Filechooser.Utils.UI;
|
|
||||||
using KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
|
using KeePassLib.Utility;
|
||||||
using keepass2android.Io;
|
using keepass2android.Io;
|
||||||
using Environment = Android.OS.Environment;
|
using keepass2android.Utils;
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
[Activity(Label = "")]
|
[Activity(Label = "")]
|
||||||
public class SelectStorageLocationActivity : Activity, IDialogInterfaceOnDismissListener
|
public class SelectStorageLocationActivity : SelectStorageLocationActivityBase, IDialogInterfaceOnDismissListener
|
||||||
{
|
{
|
||||||
private ActivityDesign _design;
|
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
|
private const string BundleKeySelectedIoc = "BundleKeySelectedIoc";
|
||||||
{
|
|
||||||
ReadOnly = 0,
|
|
||||||
WriteDesired = 1,
|
|
||||||
WriteDemanded = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
public const string ExtraKeyWritableRequirements = "EXTRA_KEY_WRITABLE_REQUIREMENTS";
|
public const string ExtraKeyWritableRequirements = "EXTRA_KEY_WRITABLE_REQUIREMENTS";
|
||||||
|
|
||||||
public SelectStorageLocationActivity()
|
public SelectStorageLocationActivity() : base(App.Kp2a)
|
||||||
{
|
{
|
||||||
_design = new ActivityDesign(this);
|
_design = new ActivityDesign(this);
|
||||||
}
|
}
|
||||||
@ -58,6 +42,8 @@ namespace keepass2android
|
|||||||
|
|
||||||
bool allowThirdPartyGet = Intent.GetBooleanExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, false);
|
bool allowThirdPartyGet = Intent.GetBooleanExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, false);
|
||||||
bool allowThirdPartySend = Intent.GetBooleanExtra(FileStorageSelectionActivity.AllowThirdPartyAppSend, false);
|
bool allowThirdPartySend = Intent.GetBooleanExtra(FileStorageSelectionActivity.AllowThirdPartyAppSend, false);
|
||||||
|
|
||||||
|
bool isRecreated = false;
|
||||||
if (bundle == null)
|
if (bundle == null)
|
||||||
State = new Bundle();
|
State = new Bundle();
|
||||||
else
|
else
|
||||||
@ -66,15 +52,14 @@ namespace keepass2android
|
|||||||
var selectedIocString = bundle.GetString(BundleKeySelectedIoc, null);
|
var selectedIocString = bundle.GetString(BundleKeySelectedIoc, null);
|
||||||
if (selectedIocString != null)
|
if (selectedIocString != null)
|
||||||
_selectedIoc = IOConnectionInfo.UnserializeFromString(selectedIocString);
|
_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));
|
StartFileStorageSelection(RequestCodeFileStorageSelectionForPrimarySelect, allowThirdPartyGet, allowThirdPartySend);
|
||||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, allowThirdPartyGet);
|
|
||||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppSend, allowThirdPartySend);
|
|
||||||
StartActivityForResult(intent, RequestCodeFileStorageSelectionForPrimarySelect);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -82,7 +67,58 @@ namespace keepass2android
|
|||||||
|
|
||||||
protected Bundle State { get; set; }
|
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); }
|
get { return Intent.GetBooleanExtra(FileStorageSetupDefs.ExtraIsForSave, false); }
|
||||||
}
|
}
|
||||||
@ -103,241 +139,14 @@ namespace keepass2android
|
|||||||
_design.ReapplyTheme();
|
_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)
|
protected override void ReturnCancel()
|
||||||
{
|
|
||||||
|
|
||||||
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()
|
|
||||||
{
|
{
|
||||||
SetResult(Result.Canceled);
|
SetResult(Result.Canceled);
|
||||||
Finish();
|
Finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void IocSelected(IOConnectionInfo ioc, int requestCode)
|
protected override void ReturnOk(IOConnectionInfo ioc)
|
||||||
{
|
|
||||||
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();
|
Intent intent = new Intent();
|
||||||
PasswordActivity.PutIoConnectionToIntent(ioc, intent);
|
PasswordActivity.PutIoConnectionToIntent(ioc, intent);
|
||||||
@ -345,42 +154,52 @@ namespace keepass2android
|
|||||||
Finish();
|
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); }
|
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 intent = new Intent(this, typeof(FileStorageSelectionActivity));
|
||||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, false);
|
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, allowThirdPartyGet);
|
||||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppSend, false);
|
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppSend, allowThirdPartySend);
|
||||||
|
|
||||||
StartActivityForResult(intent, RequestCodeFileStorageSelectionForCopyToWritableLocation);
|
|
||||||
|
|
||||||
|
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
|
#if !EXCLUDE_FILECHOOSER
|
||||||
StartFileChooser(ioc.Path, requestCode, isForSave);
|
Kp2aLog.Log("FSA: defaultPath=" + defaultPath);
|
||||||
#else
|
|
||||||
IocSelected(ioc, requestCode);
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !EXCLUDE_FILECHOOSER
|
|
||||||
private void StartFileChooser(string defaultPath, int requestCode, bool forSave)
|
|
||||||
{
|
|
||||||
Kp2aLog.Log("FSA: defaultPath="+defaultPath);
|
|
||||||
string fileProviderAuthority = FileChooserFileProvider.TheAuthority;
|
string fileProviderAuthority = FileChooserFileProvider.TheAuthority;
|
||||||
if (defaultPath.StartsWith("file://"))
|
if (defaultPath.StartsWith("file://"))
|
||||||
{
|
{
|
||||||
fileProviderAuthority = PackageName+".android-filechooser.localfile";
|
fileProviderAuthority = PackageName + ".android-filechooser.localfile";
|
||||||
}
|
}
|
||||||
Intent i = Keepass2android.Kp2afilechooser.Kp2aFileChooserBridge.GetLaunchFileChooserIntent(this, fileProviderAuthority,
|
Intent i = Keepass2android.Kp2afilechooser.Kp2aFileChooserBridge.GetLaunchFileChooserIntent(this, fileProviderAuthority,
|
||||||
defaultPath);
|
defaultPath);
|
||||||
@ -389,31 +208,26 @@ namespace keepass2android
|
|||||||
if (forSave)
|
if (forSave)
|
||||||
{
|
{
|
||||||
i.PutExtra("group.pals.android.lib.ui.filechooser.FileChooserActivity.save_dialog", true);
|
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);
|
StartActivityForResult(i, requestCode);
|
||||||
|
|
||||||
|
#else
|
||||||
|
IocSelected(new IOConnectionInfo { Path = "/mnt/sdcard/keepass/yubi.kdbx" }, requestCode);
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#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)
|
public void OnDismiss(IDialogInterface dialog)
|
||||||
{
|
{
|
||||||
// ReturnCancel();
|
// ReturnCancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -345,7 +345,7 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
string filename = ((EditText) dialog.FindViewById(Resource.Id.file_filename)).Text;
|
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)
|
public IFileStorage GetFileStorage(IOConnectionInfo iocInfo)
|
||||||
|
{
|
||||||
|
return GetFileStorage(iocInfo, true);
|
||||||
|
}
|
||||||
|
public IFileStorage GetFileStorage(IOConnectionInfo iocInfo, bool allowCache)
|
||||||
{
|
{
|
||||||
if (iocInfo.IsLocalFile())
|
if (iocInfo.IsLocalFile())
|
||||||
return new BuiltInFileStorage(this);
|
return new BuiltInFileStorage(this);
|
||||||
@ -399,9 +403,8 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
IFileStorage innerFileStorage = GetCloudFileStorage(iocInfo);
|
IFileStorage innerFileStorage = GetCloudFileStorage(iocInfo);
|
||||||
|
|
||||||
if (DatabaseCacheEnabled)
|
if (DatabaseCacheEnabled && allowCache)
|
||||||
{
|
{
|
||||||
//TODO
|
|
||||||
return new CachingFileStorage(innerFileStorage, Application.Context.CacheDir.Path, this);
|
return new CachingFileStorage(innerFileStorage, Application.Context.CacheDir.Path, this);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
Loading…
Reference in New Issue
Block a user