* modified setup workflow for IFileStorage (to be compatible with Google Drive requirements)

* scheme (protocol) is always contained in path variables passed to JavaFileStorage implementors
* file chooser improvements (internal browser displayed also in file chooser list e.g. when selecting an attachments, compatible with Solid Explorer content uris, removed OI stuff)
* started GDrive support
This commit is contained in:
Philipp Crocoll
2013-10-07 06:28:06 +02:00
parent fcae4fcbb6
commit 6f22ad012e
45 changed files with 3425 additions and 2569 deletions

View File

@@ -2,16 +2,9 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
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 KeePassLib.Utility;
@@ -89,8 +82,6 @@ namespace keepass2android.Io
return new BuiltInFileTransaction(ioc, useFileTransaction);
}
public IFileStorageSetup RequiredSetup { get { return null; } }
public class BuiltInFileTransaction : IWriteTransaction
{
private readonly FileTransactionEx _transaction;
@@ -155,5 +146,54 @@ namespace keepass2android.Io
//TODO
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)
{
if (protocolId != "file")
activity.PerformManualFileSelect(isForSave, requestCode, protocolId);
else
{
Intent intent = new Intent();
activity.IocToIntent(intent, new IOConnectionInfo() { Path = protocolId+"://"});
activity.OnImmediateResult(requestCode, (int) FileStorageResults.FileChooserPrepared, intent);
}
}
public void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode)
{
Intent intent = new Intent();
activity.IocToIntent(intent, ioc);
activity.OnImmediateResult(requestCode, (int) FileStorageResults.FileUsagePrepared, intent);
}
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();
}
}
}

View File

@@ -4,6 +4,8 @@ using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using Android.Content;
using Android.OS;
using KeePassLib.Cryptography;
using KeePassLib.Serialization;
using KeePassLib.Utility;
@@ -19,7 +21,7 @@ namespace keepass2android.Io
/// called when a save operation only updated the cache but not the remote file
/// </summary>
/// <param name="ioc">The file which we tried to write</param>
/// <param name="e">The exception why the remote file couldn't be updated</param>
/// <param name="ex">The exception why the remote file couldn't be updated</param>
void CouldntSaveToRemote(IOConnectionInfo ioc, Exception ex);
/// <summary>
@@ -398,8 +400,6 @@ namespace keepass2android.Io
return new CachedWriteTransaction(ioc, useFileTransaction, this);
}
public IFileStorageSetup RequiredSetup { get { return _cachedStorage.RequiredSetup; } }
public bool CompleteIoId()
{
throw new NotImplementedException();
@@ -436,6 +436,46 @@ namespace keepass2android.Io
return _cachedStorage.GetFileDescription(ioc);
}
public bool RequiresSetup(IOConnectionInfo ioConnection)
{
return _cachedStorage.RequiresSetup(ioConnection);
}
public string IocToPath(IOConnectionInfo ioc)
{
return _cachedStorage.IocToPath(ioc);
}
public void StartSelectFile(IFileStorageSetupInitiatorActivity activity, bool isForSave, int requestCode, string protocolId)
{
_cachedStorage.StartSelectFile(activity, isForSave, requestCode, protocolId);
}
public void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode)
{
_cachedStorage.PrepareFileUsage(activity, ioc, requestCode);
}
public void OnCreate(IFileStorageSetupActivity activity, Bundle savedInstanceState)
{
_cachedStorage.OnCreate(activity, savedInstanceState);
}
public void OnResume(IFileStorageSetupActivity activity)
{
_cachedStorage.OnResume(activity);
}
public void OnStart(IFileStorageSetupActivity activity)
{
_cachedStorage.OnStart(activity);
}
public void OnActivityResult(IFileStorageSetupActivity activity, int requestCode, int resultCode, Intent data)
{
_cachedStorage.OnActivityResult(activity, requestCode, resultCode, data);
}
public string GetBaseVersionHash(IOConnectionInfo ioc)
{

View File

@@ -16,17 +16,14 @@ using Keepass2android.Javafilestorage;
namespace keepass2android.Io
{
public class DropboxFileStorage: JavaFileStorage
public partial class DropboxFileStorage: JavaFileStorage
{
public DropboxFileStorage(Context ctx, IKp2aApp app) :
base(new Keepass2android.Javafilestorage.DropboxFileStorage(ctx), app)
base(new Keepass2android.Javafilestorage.DropboxFileStorage(ctx, AppKey, AppSecret), app)
{
}
protected override string Protocol
{
get { return "dropbox"; }
}
}
}
#endif

View File

@@ -0,0 +1,23 @@
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 KeePassLib.Serialization;
namespace keepass2android.Io
{
public interface IFileStorageSetupActivity
{
IOConnectionInfo Ioc { get; }
String ProcessName { get; }
bool IsForSave { get; }
Bundle State { get; }
}
}

View File

@@ -0,0 +1,20 @@
using System;
using Android.App;
using Android.Content;
using Android.OS;
using KeePassLib.Serialization;
namespace keepass2android.Io
{
public interface IFileStorageSetupInitiatorActivity
{
void StartSelectFileProcess(IOConnectionInfo ioc, bool isForSave, int requestCode);
void StartFileUsageProcess(IOConnectionInfo ioc, int requestCode);
void OnImmediateResult(int requestCode, int result, Intent intent);
Activity Activity { get; }
void IocToIntent(Intent intent, IOConnectionInfo ioc);
void PerformManualFileSelect(bool isForSave, int requestCode, string protocolId);
}
}

View File

@@ -14,7 +14,7 @@ using KeePassLib.Serialization;
namespace keepass2android.Io
{
public class GDriveFileStorage: IFileStorage
/*public class GDriveFileStorage: IFileStorage
{
public IEnumerable<string> SupportedProtocols { get { yield return "gdrive"; } }
public void Delete(IOConnectionInfo ioc)
@@ -42,7 +42,6 @@ namespace keepass2android.Io
throw new NotImplementedException();
}
public IFileStorageSetup RequiredSetup { get; private set; }
public bool CompleteIoId()
{
@@ -78,5 +77,5 @@ namespace keepass2android.Io
{
throw new NotImplementedException();
}
}
}*/
}

View File

@@ -1,20 +1,33 @@
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.Keys;
using KeePassLib.Serialization;
namespace keepass2android.Io
{
public enum FileStorageResults
{
FullFilenameSelected = 874345 + 1,
FileChooserPrepared = FullFilenameSelected + 1,
FileUsagePrepared = FileChooserPrepared + 1
}
public static class FileStorageSetupDefs
{
public static String ProcessNameSelectfile = "SELECT_FILE";
public static String ProcessNameFileUsageSetup = "FILE_USAGE_SETUP";
public static String ExtraProcessName = "EXTRA_PROCESS_NAME";
public static String ExtraPath = "PATH";
public static String ExtraIsForSave = "IS_FOR_SAVE";
public static String ExtraErrorMessage = "EXTRA_ERROR_MESSAGE";
}
/// <summary>
/// Called as a callback from CheckForFileChangeAsync.
/// </summary>
@@ -69,14 +82,6 @@ namespace keepass2android.Io
/// <param name="useFileTransaction">if true, force to use file system level transaction. This might be ignored if the file storage has built in transaction support</param>
IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction);
/// <summary>
/// Returns an instance of an implementation of IFileStorageSetup or one of the more complex interfaces.
/// Depending on the type returned, the caller should try to follow the interface as close as possible.
/// Returns null if the file storage is setup or doesn't require anything to work.
/// </summary>
/// This is due to different storage types requiring different workflows for authentication processes
IFileStorageSetup RequiredSetup { get; }
/// <summary>
/// brings up a dialog to query credentials or something like this.
/// </summary>
@@ -111,32 +116,36 @@ namespace keepass2android.Io
/// returns the description of the given file
/// </summary>
FileDescription GetFileDescription(IOConnectionInfo ioc);
}
/// <summary>
/// Base interface for required setup code
/// </summary>
public interface IFileStorageSetup
{
/// <summary>
/// call this when the user explicitly wants to use this file storage. Might require user interaction.
/// May throw if the setup failed permanentaly.
/// returns true if everything is ok with connecting to the given file.
/// Returns False if PrepareFileUsage must be called first.
/// </summary>
/// <returns>true if the setup was succesful immediately (without UI). Returns false if setup was not successful but no error occured or can be displayed.</returns>
bool TrySetup(Activity activity);
}
bool RequiresSetup(IOConnectionInfo ioConnection);
/// <summary>
/// Interface which can be used additionally for an IFileStorageSetup to indicate that setup must be completed in OnResume()
/// </summary>
public interface IFileStorageSetupOnResume
{
/// <summary>
/// call this after TrySetup() returned false in the next OnResume()
/// May throw if the setup failed permanentaly.
/// converts the ioc to a path which may contain the credentials
/// </summary>
/// <returns>true if setup was succesful</returns>
bool TrySetupOnResume(Activity activity);
string IocToPath(IOConnectionInfo ioc);
/// <summary>
/// Initiates the process for choosing a file in the given file storage.
/// The file storage should either call OnImmediateResult or StartSelectFileProcess
/// </summary>
void StartSelectFile(IFileStorageSetupInitiatorActivity activity, bool isForSave, int requestCode, string protocolId);
/// <summary>
/// Initiates the process for choosing a file in the given file storage.
/// The file storage should either call OnImmediateResult or StartFileUsageProcess
/// </summary>
void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode);
//Setup methods: these are called from the setup activity so the file storage can handle UI events for authorization etc.
void OnCreate(IFileStorageSetupActivity activity, Bundle savedInstanceState);
void OnResume(IFileStorageSetupActivity activity);
void OnStart(IFileStorageSetupActivity activity);
void OnActivityResult(IFileStorageSetupActivity activity, int requestCode, int resultCode, Intent data);
}
public interface IWriteTransaction: IDisposable

View File

@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using Android.App;
using Android.Content;
using Android.OS;
using KeePassLib.Serialization;
using KeePassLib.Utility;
#if !EXCLUDE_JAVAFILESTORAGE
@@ -16,6 +18,8 @@ namespace keepass2android.Io
#if !EXCLUDE_JAVAFILESTORAGE
public abstract class JavaFileStorage: IFileStorage
{
protected string Protocol { get { return _jfs.ProtocolId; } }
public IEnumerable<string> SupportedProtocols { get { yield return Protocol; } }
@@ -64,7 +68,7 @@ namespace keepass2android.Io
{
try
{
return Jfs.GetCurrentFileVersionFast(ioc.Path);
return Jfs.GetCurrentFileVersionFast(IocToPath(ioc));
}
catch (Java.Lang.Exception e)
{
@@ -103,55 +107,11 @@ namespace keepass2android.Io
return new JavaFileStorageWriteTransaction(IocToPath(ioc), useFileTransaction, this);
}
public IFileStorageSetup RequiredSetup
{
get
{
if (Jfs.IsConnected)
return null;
return new JavaFileStorageSetup(this);
}
}
internal IJavaFileStorage Jfs
{
get { return _jfs; }
}
public class JavaFileStorageSetup : IFileStorageSetup, IFileStorageSetupOnResume
{
private readonly JavaFileStorage _javaFileStorage;
public JavaFileStorageSetup(JavaFileStorage javaFileStorage)
{
_javaFileStorage = javaFileStorage;
}
public bool TrySetup(Activity activity)
{
try
{
return _javaFileStorage.Jfs.TryConnect(activity);
}
catch (Java.Lang.Exception e)
{
throw _javaFileStorage.LogAndConvertJavaException(e);
}
}
public bool TrySetupOnResume(Activity activity)
{
try
{
_javaFileStorage.Jfs.OnResume();
return _javaFileStorage.Jfs.IsConnected;
}
catch (Java.Lang.Exception e)
{
throw _javaFileStorage.LogAndConvertJavaException(e);
}
}
}
class JavaFileStorageWriteTransaction: IWriteTransaction
{
@@ -255,13 +215,14 @@ namespace keepass2android.Io
CanWrite = e.CanWrite,
IsDirectory = e.IsDirectory,
LastModified = JavaTimeToCSharp(e.LastModifiedTime),
Path = Protocol + "://" + e.Path,
Path = e.Path,
SizeInBytes = e.SizeInBytes
};
}
public FileDescription GetFileDescription(IOConnectionInfo ioc)
{
Kp2aLog.Log("GetFileDescription "+ioc.Path);
try
{
return ConvertToFileDescription(Jfs.GetFileEntry(IocToPath(ioc)));
@@ -276,24 +237,54 @@ namespace keepass2android.Io
}
}
public bool RequiresSetup(IOConnectionInfo ioConnection)
{
return _jfs.RequiresSetup(IocToPath(ioConnection));
}
public void StartSelectFile(IFileStorageSetupInitiatorActivity activity, bool isForSave, int requestCode, string protocolId)
{
Kp2aLog.Log("StartSelectFile " + protocolId);
_jfs.StartSelectFile((IJavaFileStorageFileStorageSetupInitiatorActivity) activity, isForSave, requestCode);
}
public void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode)
{
_jfs.PrepareFileUsage((IJavaFileStorageFileStorageSetupInitiatorActivity)activity, IocToPath(ioc), requestCode);
}
public void OnCreate(IFileStorageSetupActivity activity, Bundle savedInstanceState)
{
_jfs.OnCreate(((IJavaFileStorageFileStorageSetupActivity)activity), savedInstanceState);
}
public void OnResume(IFileStorageSetupActivity activity)
{
Kp2aLog.Log("JFS/OnResume Ioc.Path=" +activity.Ioc.Path+". Path="+((IJavaFileStorageFileStorageSetupActivity)activity).Path);
_jfs.OnResume(((IJavaFileStorageFileStorageSetupActivity) activity));
}
public void OnStart(IFileStorageSetupActivity activity)
{
_jfs.OnStart(((IJavaFileStorageFileStorageSetupActivity) activity));
}
public void OnActivityResult(IFileStorageSetupActivity activity, int requestCode, int resultCode, Intent data)
{
_jfs.OnActivityResult(((IJavaFileStorageFileStorageSetupActivity) activity), requestCode, resultCode, data);
}
private DateTime JavaTimeToCSharp(long javatime)
{
//todo test
return new DateTime(1970, 1, 1).AddMilliseconds(javatime);
}
private string IocToPath(IOConnectionInfo ioc)
public string IocToPath(IOConnectionInfo ioc)
{
if (ioc.Path.StartsWith(Protocol + "://"))
return ioc.Path.Substring(Protocol.Length + 3);
else
{
return ioc.Path;
}
return ioc.Path;
}
protected abstract string Protocol { get; }
}
#endif
}

View File

@@ -20,7 +20,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;EXCLUDE_JAVAFILESTORAGE</DefineConstants>
<DefineConstants>TRACE;DEBUG;INCLUDE_TWOFISH;INCLUDE_KEYBOARD;INCLUDE_KEYTRANSFORM;INCLUDE_FILECHOOSER;INCLUDE_JAVAFILESTORAGE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
@@ -58,7 +58,10 @@
<Compile Include="Io\BuiltInFileStorage.cs" />
<Compile Include="Io\CachingFileStorage.cs" />
<Compile Include="Io\DropboxFileStorage.cs" />
<Compile Include="Io\DropboxFileStorageKeys.cs" />
<Compile Include="Io\FileDescription.cs" />
<Compile Include="Io\FileStorageSetupActivity.cs" />
<Compile Include="Io\FileStorageSetupInitiatorActivity.cs" />
<Compile Include="Io\GDriveFileStorage.cs" />
<Compile Include="Io\IFileStorage.cs" />
<Compile Include="Io\IoUtil.cs" />
@@ -93,7 +96,7 @@
<Compile Include="ProgressDialogStatusLogger.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj" Condition="!$(DefineConstants.Contains('EXCLUDE_JAVAFILESTORAGE'))">
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj">
<Project>{48574278-4779-4b3a-a9e4-9cf1bc285d0b}</Project>
<Name>JavaFileStorageBindings</Name>
</ProjectReference>