move duplicated file-browsing code to FileSelectHelper

This commit is contained in:
Philipp Crocoll 2016-11-15 05:50:26 +01:00
parent 53877a16a9
commit 86bfae57c3
6 changed files with 293 additions and 279 deletions

View File

@ -62,8 +62,8 @@ namespace keepass2android
}
else
{
bool isForSave = (requestCode == RequestCodeFileStorageSelectionForPrimarySelect) ?
IsStorageSelectionForSave : true;
bool isForSave = (requestCode != RequestCodeFileStorageSelectionForPrimarySelect)
|| IsStorageSelectionForSave;
StartSelectFile(isForSave, browseRequestCode, protocolId);
@ -85,8 +85,8 @@ namespace keepass2android
{
IOConnectionInfo ioc = new IOConnectionInfo();
SetIoConnectionFromIntent(ioc, data);
bool isForSave = (requestCode == RequestCodeFileFileBrowseForWritableLocation) ?
true : IsStorageSelectionForSave;
bool isForSave = (requestCode == RequestCodeFileFileBrowseForWritableLocation)
|| IsStorageSelectionForSave;
StartFileChooser(ioc.Path, requestCode, isForSave);
@ -164,6 +164,8 @@ namespace keepass2android
}
protected abstract void StartFileChooser(string path, int requestCode, bool isForSave);
protected abstract void ShowToast(string text);
protected abstract void ShowInvalidSchemeMessage(string dataString);
@ -187,7 +189,7 @@ namespace keepass2android
protected abstract bool IsStorageSelectionForSave { get; }
private void IocSelected(IOConnectionInfo ioc, int requestCode)
protected void IocSelected(IOConnectionInfo ioc, int requestCode)
{
if (requestCode == RequestCodeFileFileBrowseForWritableLocation)
{
@ -245,44 +247,6 @@ namespace keepass2android
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, Action dismissDialog)
{
IOConnectionInfo ioc = new IOConnectionInfo
{
Path = fileName
};
int lastSlashPos = fileName.LastIndexOf('/');
int lastDotPos = fileName.LastIndexOf('.');
if (lastSlashPos >= lastDotPos) //no dot after last slash or == in case neither / nor .
{
ShowFilenameWarning(fileName, () => { IocSelected(ioc, requestCode); dismissDialog(); }, () => { /* don't do anything, leave dialog open, let user try again*/ });
//signal that the dialog should be kept open
return false;
}
IocSelected(ioc, requestCode);
return true;
}
protected abstract void ShowFilenameWarning(string fileName, Action onUserWantsToContinue, Action onUserWantsToCorrect);
protected virtual void CopyFile(IOConnectionInfo targetIoc, IOConnectionInfo sourceIoc)
{

View File

@ -111,7 +111,7 @@ namespace keepass2android
defaulFilename = "file://" + defaulFilename;
}
StartFileChooser(defaulFilename, RequestCodeKeyFile, false);
new FileSelectHelper(this, false, RequestCodeKeyFile).StartFileChooser(defaulFilename);
}
else
@ -244,28 +244,6 @@ namespace keepass2android
_restoringInstanceState = false;
}
private void StartFileChooser(string defaultPath, int requestCode, bool forSave)
{
#if !EXCLUDE_FILECHOOSER
Kp2aLog.Log("FSA: defaultPath=" + defaultPath);
string fileProviderAuthority = FileChooserFileProvider.TheAuthority;
if (defaultPath.StartsWith("file://"))
{
fileProviderAuthority = "keepass2android."+AppNames.PackagePart+".android-filechooser.localfile";
}
Intent i = Keepass2android.Kp2afilechooser.Kp2aFileChooserBridge.GetLaunchFileChooserIntent(this, fileProviderAuthority,
defaultPath);
if (forSave)
{
i.PutExtra("group.pals.android.lib.ui.filechooser.FileChooserActivity.save_dialog", true);
i.PutExtra("group.pals.android.lib.ui.filechooser.FileChooserActivity.default_file_ext", "kdbx");
}
StartActivityForResult(i, requestCode);
#endif
}
private void UpdateIocView()
{
@ -343,17 +321,20 @@ namespace keepass2android
}
else
{
App.Kp2a.GetFileStorage(protocolId).StartSelectFile(new FileStorageSetupInitiatorActivity(this,
OnActivityResult,
defaultPath =>
FileSelectHelper fileSelectHelper = new FileSelectHelper(this, true, RequestCodeDbFilename)
{
if (defaultPath.StartsWith("sftp://"))
Util.ShowSftpDialog(this, OnReceiveSftpData, () => { });
else
Util.ShowFilenameDialog(this, OnCreateButton, null, null, false, defaultPath, GetString(Resource.String.enter_filename_details_url),
Intents.RequestCodeFileBrowseForOpen);
}
), true, RequestCodeDbFilename, protocolId);
DefaultExtension = "kdbx"
};
fileSelectHelper.OnOpen += (sender, info) =>
{
_ioc = info;
UpdateIocView();
};
App.Kp2a.GetFileStorage(protocolId).StartSelectFile(
new FileStorageSetupInitiatorActivity(this,OnActivityResult,s => fileSelectHelper.PerformManualFileSelect(s)),
true,
RequestCodeDbFilename,
protocolId);
}
}
@ -436,16 +417,14 @@ namespace keepass2android
{
IOConnectionInfo ioc = new IOConnectionInfo();
PasswordActivity.SetIoConnectionFromIntent(ioc, data);
StartFileChooser(ioc.Path, RequestCodeDbFilename, true);
new FileSelectHelper(this, true, RequestCodeDbFilename) { DefaultExtension = "kdbx" }
.StartFileChooser(ioc.Path);
}
}
private bool OnReceiveSftpData(string filename)
{
StartFileChooser(filename, RequestCodeDbFilename, true);
return true;
}
private static string ConvertFilenameToIocPath(string filename)
{
@ -457,86 +436,6 @@ namespace keepass2android
return filename;
}
private bool OnCreateButton(string filename, Dialog dialog)
{
// Make sure file name exists
if (filename.Length == 0)
{
Toast.MakeText(this,
Resource.String.error_filename_required,
ToastLength.Long).Show();
return false;
}
IOConnectionInfo ioc = new IOConnectionInfo { Path = filename };
IFileStorage fileStorage;
try
{
fileStorage = App.Kp2a.GetFileStorage(ioc);
}
catch (NoFileStorageFoundException)
{
Toast.MakeText(this,
"Unexpected scheme in "+filename,
ToastLength.Long).Show();
return false;
}
if (ioc.IsLocalFile())
{
// Try to create the file
File file = new File(filename);
try
{
File parent = file.ParentFile;
if (parent == null || (parent.Exists() && !parent.IsDirectory))
{
Toast.MakeText(this,
Resource.String.error_invalid_path,
ToastLength.Long).Show();
return false;
}
if (!parent.Exists())
{
// Create parent dircetory
if (!parent.Mkdirs())
{
Toast.MakeText(this,
Resource.String.error_could_not_create_parent,
ToastLength.Long).Show();
return false;
}
}
System.IO.File.Create(filename);
}
catch (IOException ex)
{
Toast.MakeText(
this,
GetText(Resource.String.error_file_not_create) + " "
+ ex.LocalizedMessage,
ToastLength.Long).Show();
return false;
}
}
if (fileStorage.RequiresCredentials(ioc))
{
Util.QueryCredentials(ioc, AfterQueryCredentials, this);
}
else
{
_ioc = ioc;
UpdateIocView();
}
return true;
}
private void AfterQueryCredentials(IOConnectionInfo ioc)
{

View File

@ -62,17 +62,19 @@ namespace keepass2android
}
else
{
App.Kp2a.GetFileStorage(protocolId).StartSelectFile(new FileStorageSetupInitiatorActivity(this,
OnActivityResult,
defaultPath =>
FileSelectHelper fileSelectHelper = new FileSelectHelper(this, true, RequestCodeDbFilename)
{
if (defaultPath.StartsWith("sftp://"))
Util.ShowSftpDialog(this, OnReceiveSftpData, () => { });
else
Util.ShowFilenameDialog(this, OnCreateButton, null, null, false, defaultPath, GetString(Resource.String.enter_filename_details_url),
Intents.RequestCodeFileBrowseForOpen);
}
), true, RequestCodeDbFilename, protocolId);
DefaultExtension = _ffp[_fileFormatIndex].DefaultExtension
};
fileSelectHelper.OnOpen += (sender, ioc) =>
{
ExportTo(ioc);
};
App.Kp2a.GetFileStorage(protocolId).StartSelectFile(
new FileStorageSetupInitiatorActivity(this, OnActivityResult, s => fileSelectHelper.PerformManualFileSelect(s)),
true,
RequestCodeDbFilename,
protocolId);
}
return;
}
@ -149,7 +151,9 @@ namespace keepass2android
{
IOConnectionInfo ioc = new IOConnectionInfo();
PasswordActivity.SetIoConnectionFromIntent(ioc, data);
StartFileChooser(ioc.Path, RequestCodeDbFilename, true);
new FileSelectHelper(this, true, RequestCodeDbFilename)
{ DefaultExtension = _ffp[_fileFormatIndex].DefaultExtension}
.StartFileChooser(ioc.Path);
return;
}
Finish();
@ -176,39 +180,6 @@ namespace keepass2android
get { return 0; }
}
private bool OnCreateButton(string filename, Dialog dialog)
{
if (filename.Length == 0)
{
Toast.MakeText(this,
Resource.String.error_filename_required,
ToastLength.Long).Show();
return false;
}
IOConnectionInfo ioc = new IOConnectionInfo { Path = filename };
try
{
App.Kp2a.GetFileStorage(ioc);
}
catch (NoFileStorageFoundException)
{
Toast.MakeText(this,
"Unexpected scheme in " + filename,
ToastLength.Long).Show();
return false;
}
ExportTo(new IOConnectionInfo() { Path = filename });
return true;
}
private bool OnReceiveSftpData(string filename)
{
StartFileChooser(filename, RequestCodeDbFilename, true);
return true;
}
private static string ConvertFilenameToIocPath(string filename)
{
if ((filename != null) && (filename.StartsWith("file://")))
@ -219,29 +190,6 @@ namespace keepass2android
return filename;
}
private void StartFileChooser(string defaultPath, int requestCode, bool forSave)
{
#if !EXCLUDE_FILECHOOSER
Kp2aLog.Log("FSA: defaultPath=" + defaultPath);
string fileProviderAuthority = FileChooserFileProvider.TheAuthority;
if (defaultPath.StartsWith("file://"))
{
fileProviderAuthority = "keepass2android."+AppNames.PackagePart+".android-filechooser.localfile";
}
Intent i = Keepass2android.Kp2afilechooser.Kp2aFileChooserBridge.GetLaunchFileChooserIntent(this, fileProviderAuthority,
defaultPath);
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", _ffp[_fileFormatIndex].DefaultExtension);
}
StartActivityForResult(i, requestCode);
#endif
}
public class ExportDb : RunnableOnFinish
{
private readonly IKp2aApp _app;

View File

@ -0,0 +1,242 @@
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 Java.IO;
using keepass2android.Io;
using KeePassLib.Serialization;
using KeePassLib.Utility;
namespace keepass2android
{
public class FileSelectHelper
{
private readonly Activity _activity;
private readonly bool _isForSave;
private readonly int _requestCode;
public string DefaultExtension { get; set; }
public FileSelectHelper(Activity activity, bool isForSave, int requestCode)
{
_activity = activity;
_isForSave = isForSave;
_requestCode = requestCode;
}
private void ShowSftpDialog(Activity activity, Util.FileSelectedHandler onStartBrowse, Action onCancel)
{
#if !EXCLUDE_JAVAFILESTORAGE && !NoNet
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
View dlgContents = activity.LayoutInflater.Inflate(Resource.Layout.sftpcredentials, null);
builder.SetView(dlgContents);
builder.SetPositiveButton(Android.Resource.String.Ok,
(sender, args) =>
{
string host = dlgContents.FindViewById<EditText>(Resource.Id.sftp_host).Text;
string portText = dlgContents.FindViewById<EditText>(Resource.Id.sftp_port).Text;
int port = Keepass2android.Javafilestorage.SftpStorage.DefaultSftpPort;
if (!string.IsNullOrEmpty(portText))
int.TryParse(portText, out port);
string user = dlgContents.FindViewById<EditText>(Resource.Id.sftp_user).Text;
string password = dlgContents.FindViewById<EditText>(Resource.Id.sftp_password).Text;
string initialPath = dlgContents.FindViewById<EditText>(Resource.Id.sftp_initial_dir).Text;
string sftpPath = new Keepass2android.Javafilestorage.SftpStorage().BuildFullPath(host, port, initialPath, user,
password);
onStartBrowse(sftpPath);
});
EventHandler<DialogClickEventArgs> evtH = new EventHandler<DialogClickEventArgs>((sender, e) => onCancel());
builder.SetNegativeButton(Android.Resource.String.Cancel, evtH);
builder.SetTitle(activity.GetString(Resource.String.enter_sftp_login_title));
Dialog dialog = builder.Create();
dialog.Show();
#endif
}
public void PerformManualFileSelect(string defaultPath)
{
if (defaultPath.StartsWith("sftp://"))
ShowSftpDialog(_activity, StartFileChooser, ReturnCancel);
else
{
Func<string, Dialog, bool> onOpen = (filename, dialog) => OnOpenButton(filename, dialog);
Util.ShowFilenameDialog(_activity,
!_isForSave ? onOpen : null,
_isForSave ? onOpen : null,
ReturnCancel,
false,
defaultPath,
_activity.GetString(Resource.String.enter_filename_details_url),
_requestCode)
;
}
}
private void ReturnCancel()
{
if (OnCancel != null)
OnCancel(this, null);
}
protected void ShowFilenameWarning(string fileName, Action onUserWantsToContinue, Action onUserWantsToCorrect)
{
new AlertDialog.Builder(_activity)
.SetPositiveButton(keepass2android.Resource.String.Continue, delegate { onUserWantsToContinue(); })
.SetMessage(Resource.String.NoFilenameWarning)
.SetCancelable(false)
.SetNegativeButton(Android.Resource.String.Cancel, delegate { onUserWantsToCorrect(); })
.Create()
.Show();
}
private bool OnOpenButton(string filename, Dialog dialog)
{
IOConnectionInfo ioc = new IOConnectionInfo
{
Path = filename
};
// Make sure file name exists
if (filename.Length == 0)
{
Toast.MakeText(_activity,
Resource.String.error_filename_required,
ToastLength.Long).Show();
return false;
}
int lastSlashPos = filename.LastIndexOf('/');
int lastDotPos = filename.LastIndexOf('.');
if (lastSlashPos >= lastDotPos) //no dot after last slash or == in case neither / nor .
{
ShowFilenameWarning(filename, () => { IocSelected(ioc); dialog.Dismiss(); }, () => { /* don't do anything, leave dialog open, let user try again*/ });
//signal that the dialog should be kept open
return false;
}
IFileStorage fileStorage;
try
{
fileStorage = App.Kp2a.GetFileStorage(ioc);
}
catch (NoFileStorageFoundException)
{
Toast.MakeText(_activity,
"Unexpected scheme in "+filename,
ToastLength.Long).Show();
return false;
}
if (_isForSave && ioc.IsLocalFile())
{
// Try to create the file
File file = new File(filename);
try
{
File parent = file.ParentFile;
if (parent == null || (parent.Exists() && !parent.IsDirectory))
{
Toast.MakeText(_activity,
Resource.String.error_invalid_path,
ToastLength.Long).Show();
return false;
}
if (!parent.Exists())
{
// Create parent dircetory
if (!parent.Mkdirs())
{
Toast.MakeText(_activity,
Resource.String.error_could_not_create_parent,
ToastLength.Long).Show();
return false;
}
}
System.IO.File.Create(filename);
}
catch (IOException ex)
{
Toast.MakeText(
_activity,
_activity.GetText(Resource.String.error_file_not_create) + " "
+ ex.LocalizedMessage,
ToastLength.Long).Show();
return false;
}
}
if (fileStorage.RequiresCredentials(ioc))
{
Util.QueryCredentials(ioc, IocSelected, _activity);
}
else
{
IocSelected(ioc);
}
return true;
}
private void IocSelected(IOConnectionInfo ioc)
{
if (OnOpen != null)
OnOpen(this, ioc);
}
public bool StartFileChooser(string defaultPath)
{
#if !EXCLUDE_FILECHOOSER
Kp2aLog.Log("FSA: defaultPath=" + defaultPath);
string fileProviderAuthority = FileChooserFileProvider.TheAuthority;
if (defaultPath.StartsWith("file://"))
{
fileProviderAuthority = _activity.PackageName + ".android-filechooser.localfile";
}
Intent i = Keepass2android.Kp2afilechooser.Kp2aFileChooserBridge.GetLaunchFileChooserIntent(_activity, fileProviderAuthority,
defaultPath);
if (_isForSave)
{
i.PutExtra("group.pals.android.lib.ui.filechooser.FileChooserActivity.save_dialog", true);
string ext;
if (!string.IsNullOrEmpty(DefaultExtension))
{
ext = DefaultExtension;
}
else
{
ext = UrlUtil.GetExtension(defaultPath);
}
if ((ext != String.Empty) && (ext.Contains("?") == false))
i.PutExtra("group.pals.android.lib.ui.filechooser.FileChooserActivity.default_file_ext", ext);
}
_activity.StartActivityForResult(i, _requestCode);
#else
Toast.MakeText(this, "File chooser is excluded!", ToastLength.Long).Show();
#endif
return true;
}
public event EventHandler OnCancel;
public event EventHandler<IOConnectionInfo> OnOpen;
}
}

View File

@ -96,21 +96,15 @@ namespace keepass2android
protected override void StartSelectFile( bool isForSave, int browseRequestCode, string protocolId)
{
var startManualFileSelect = new Action<string>(defaultPath =>
FileSelectHelper fileSelectHelper = new FileSelectHelper(this, isForSave, browseRequestCode);
fileSelectHelper.OnOpen += (sender, ioc) =>
{
if (defaultPath.StartsWith("sftp://"))
Util.ShowSftpDialog(this, filename => OnReceivedSftpData(filename, browseRequestCode, isForSave), ReturnCancel);
else
Util.ShowFilenameDialog(this,
!isForSave ? delegate(string filename, Dialog dialog) { return OnOpenButton(filename, browseRequestCode, dialog.Dismiss); } : (Func<string, Dialog, bool>) null,
isForSave ? delegate(string filename, Dialog dialog) { return OnOpenButton(filename, browseRequestCode, dialog.Dismiss); } : (Func<string, Dialog, bool>) null,
ReturnCancel, false, defaultPath, GetString(Resource.String.enter_filename_details_url),
browseRequestCode);
});
;
IocSelected(ioc,browseRequestCode);
};
App.Kp2a.GetFileStorage(protocolId).StartSelectFile(new FileStorageSetupInitiatorActivity(this,
OnActivityResult,
startManualFileSelect
s => fileSelectHelper.PerformManualFileSelect(s)
), isForSave, browseRequestCode, protocolId);
}
@ -199,43 +193,9 @@ namespace keepass2android
protected override void StartFileChooser(string defaultPath, int requestCode, bool forSave)
{
#if !EXCLUDE_FILECHOOSER
Kp2aLog.Log("FSA: defaultPath=" + defaultPath);
string fileProviderAuthority = FileChooserFileProvider.TheAuthority;
if (defaultPath.StartsWith("file://"))
{
fileProviderAuthority = PackageName + ".android-filechooser.localfile";
}
Intent i = Keepass2android.Kp2afilechooser.Kp2aFileChooserBridge.GetLaunchFileChooserIntent(this, fileProviderAuthority,
defaultPath);
if (forSave)
{
i.PutExtra("group.pals.android.lib.ui.filechooser.FileChooserActivity.save_dialog", true);
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
Toast.MakeText(this, "File chooser is excluded!", ToastLength.Long).Show();
#endif
new FileSelectHelper(this, forSave, requestCode).StartFileChooser(defaultPath);
}
protected override void ShowFilenameWarning(string fileName, Action onUserWantsToContinue, Action onUserWantsToCorrect)
{
new AlertDialog.Builder(this)
.SetPositiveButton(Resource.String.Continue, delegate { onUserWantsToContinue(); } )
.SetMessage(Resource.String.NoFilenameWarning)
.SetCancelable(false)
.SetNegativeButton(Android.Resource.String.Cancel, delegate { onUserWantsToCorrect(); })
.Create()
.Show();
}
public void OnDismiss(IDialogInterface dialog)

View File

@ -149,6 +149,7 @@
<Compile Include="EntryActivityClasses\StandardStringView.cs" />
<Compile Include="EntryActivityClasses\ToggleVisibilityPopupMenuItem.cs" />
<Compile Include="EntryActivityClasses\WriteBinaryToFilePopupItem.cs" />
<Compile Include="FileSelectHelper.cs" />
<Compile Include="FingerprintModule.cs" />
<Compile Include="FingerprintSamsungIdentifier.cs" />
<Compile Include="FingerprintSetupActivity.cs" />