* 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
@ -20,7 +20,7 @@
|
|||||||
<DebugType>full</DebugType>
|
<DebugType>full</DebugType>
|
||||||
<Optimize>False</Optimize>
|
<Optimize>False</Optimize>
|
||||||
<OutputPath>bin\Debug</OutputPath>
|
<OutputPath>bin\Debug</OutputPath>
|
||||||
<DefineConstants>DEBUG;EXCLUDE_KEYTRANSFORM</DefineConstants>
|
<DefineConstants>DEBUG;INCLUDE_TWOFISH;INCLUDE_KEYBOARD;INCLUDE_KEYTRANSFORM;INCLUDE_FILECHOOSER;INCLUDE_JAVAFILESTORAGE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<ConsolePause>False</ConsolePause>
|
<ConsolePause>False</ConsolePause>
|
||||||
@ -155,7 +155,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
|
<Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\kp2akeytransform\kp2akeytransform.csproj" Condition="!$(DefineConstants.Contains('EXCLUDE_KEYTRANSFORM'))">
|
<ProjectReference Include="..\kp2akeytransform\kp2akeytransform.csproj" Condition="!$(DefineConstants.Contains('EXCLUDE_KEYTRANSFORM'))">
|
||||||
<Project>{A57B3ACE-5634-469A-88C4-858BB409F356}</Project>
|
<Project>{A57B3ACE-5634-469A-88C4-858BB409F356}</Project>
|
||||||
<Name>kp2akeytransform</Name>
|
<Name>kp2akeytransform</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
@ -2,16 +2,9 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
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 KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
using KeePassLib.Utility;
|
using KeePassLib.Utility;
|
||||||
|
|
||||||
@ -89,8 +82,6 @@ namespace keepass2android.Io
|
|||||||
return new BuiltInFileTransaction(ioc, useFileTransaction);
|
return new BuiltInFileTransaction(ioc, useFileTransaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IFileStorageSetup RequiredSetup { get { return null; } }
|
|
||||||
|
|
||||||
public class BuiltInFileTransaction : IWriteTransaction
|
public class BuiltInFileTransaction : IWriteTransaction
|
||||||
{
|
{
|
||||||
private readonly FileTransactionEx _transaction;
|
private readonly FileTransactionEx _transaction;
|
||||||
@ -155,5 +146,54 @@ namespace keepass2android.Io
|
|||||||
//TODO
|
//TODO
|
||||||
throw new NotImplementedException();
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,6 +4,8 @@ using System.IO;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.OS;
|
||||||
using KeePassLib.Cryptography;
|
using KeePassLib.Cryptography;
|
||||||
using KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
using KeePassLib.Utility;
|
using KeePassLib.Utility;
|
||||||
@ -19,7 +21,7 @@ namespace keepass2android.Io
|
|||||||
/// called when a save operation only updated the cache but not the remote file
|
/// called when a save operation only updated the cache but not the remote file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ioc">The file which we tried to write</param>
|
/// <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);
|
void CouldntSaveToRemote(IOConnectionInfo ioc, Exception ex);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -398,8 +400,6 @@ namespace keepass2android.Io
|
|||||||
return new CachedWriteTransaction(ioc, useFileTransaction, this);
|
return new CachedWriteTransaction(ioc, useFileTransaction, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IFileStorageSetup RequiredSetup { get { return _cachedStorage.RequiredSetup; } }
|
|
||||||
|
|
||||||
public bool CompleteIoId()
|
public bool CompleteIoId()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@ -436,6 +436,46 @@ namespace keepass2android.Io
|
|||||||
return _cachedStorage.GetFileDescription(ioc);
|
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)
|
public string GetBaseVersionHash(IOConnectionInfo ioc)
|
||||||
{
|
{
|
||||||
|
@ -16,17 +16,14 @@ using Keepass2android.Javafilestorage;
|
|||||||
|
|
||||||
namespace keepass2android.Io
|
namespace keepass2android.Io
|
||||||
{
|
{
|
||||||
public class DropboxFileStorage: JavaFileStorage
|
public partial class DropboxFileStorage: JavaFileStorage
|
||||||
{
|
{
|
||||||
public DropboxFileStorage(Context ctx, IKp2aApp app) :
|
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
|
#endif
|
23
src/Kp2aBusinessLogic/Io/FileStorageSetupActivity.cs
Normal 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; }
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,7 @@ using KeePassLib.Serialization;
|
|||||||
|
|
||||||
namespace keepass2android.Io
|
namespace keepass2android.Io
|
||||||
{
|
{
|
||||||
public class GDriveFileStorage: IFileStorage
|
/*public class GDriveFileStorage: IFileStorage
|
||||||
{
|
{
|
||||||
public IEnumerable<string> SupportedProtocols { get { yield return "gdrive"; } }
|
public IEnumerable<string> SupportedProtocols { get { yield return "gdrive"; } }
|
||||||
public void Delete(IOConnectionInfo ioc)
|
public void Delete(IOConnectionInfo ioc)
|
||||||
@ -42,7 +42,6 @@ namespace keepass2android.Io
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IFileStorageSetup RequiredSetup { get; private set; }
|
|
||||||
|
|
||||||
public bool CompleteIoId()
|
public bool CompleteIoId()
|
||||||
{
|
{
|
||||||
@ -78,5 +77,5 @@ namespace keepass2android.Io
|
|||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
@ -1,20 +1,33 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
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 KeePassLib.Keys;
|
|
||||||
using KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
|
|
||||||
namespace keepass2android.Io
|
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>
|
/// <summary>
|
||||||
/// Called as a callback from CheckForFileChangeAsync.
|
/// Called as a callback from CheckForFileChangeAsync.
|
||||||
/// </summary>
|
/// </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>
|
/// <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);
|
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>
|
/// <summary>
|
||||||
/// brings up a dialog to query credentials or something like this.
|
/// brings up a dialog to query credentials or something like this.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -111,32 +116,36 @@ namespace keepass2android.Io
|
|||||||
/// returns the description of the given file
|
/// returns the description of the given file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FileDescription GetFileDescription(IOConnectionInfo ioc);
|
FileDescription GetFileDescription(IOConnectionInfo ioc);
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Base interface for required setup code
|
|
||||||
/// </summary>
|
|
||||||
public interface IFileStorageSetup
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// call this when the user explicitly wants to use this file storage. Might require user interaction.
|
/// returns true if everything is ok with connecting to the given file.
|
||||||
/// May throw if the setup failed permanentaly.
|
/// Returns False if PrepareFileUsage must be called first.
|
||||||
/// </summary>
|
/// </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 RequiresSetup(IOConnectionInfo ioConnection);
|
||||||
bool TrySetup(Activity activity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Interface which can be used additionally for an IFileStorageSetup to indicate that setup must be completed in OnResume()
|
|
||||||
/// </summary>
|
|
||||||
public interface IFileStorageSetupOnResume
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// call this after TrySetup() returned false in the next OnResume()
|
/// converts the ioc to a path which may contain the credentials
|
||||||
/// May throw if the setup failed permanentaly.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>true if setup was succesful</returns>
|
string IocToPath(IOConnectionInfo ioc);
|
||||||
bool TrySetupOnResume(Activity activity);
|
|
||||||
|
/// <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
|
public interface IWriteTransaction: IDisposable
|
||||||
|
@ -3,6 +3,8 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Android.App;
|
using Android.App;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.OS;
|
||||||
using KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
using KeePassLib.Utility;
|
using KeePassLib.Utility;
|
||||||
#if !EXCLUDE_JAVAFILESTORAGE
|
#if !EXCLUDE_JAVAFILESTORAGE
|
||||||
@ -16,6 +18,8 @@ namespace keepass2android.Io
|
|||||||
#if !EXCLUDE_JAVAFILESTORAGE
|
#if !EXCLUDE_JAVAFILESTORAGE
|
||||||
public abstract class JavaFileStorage: IFileStorage
|
public abstract class JavaFileStorage: IFileStorage
|
||||||
{
|
{
|
||||||
|
protected string Protocol { get { return _jfs.ProtocolId; } }
|
||||||
|
|
||||||
public IEnumerable<string> SupportedProtocols { get { yield return Protocol; } }
|
public IEnumerable<string> SupportedProtocols { get { yield return Protocol; } }
|
||||||
|
|
||||||
|
|
||||||
@ -64,7 +68,7 @@ namespace keepass2android.Io
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return Jfs.GetCurrentFileVersionFast(ioc.Path);
|
return Jfs.GetCurrentFileVersionFast(IocToPath(ioc));
|
||||||
}
|
}
|
||||||
catch (Java.Lang.Exception e)
|
catch (Java.Lang.Exception e)
|
||||||
{
|
{
|
||||||
@ -103,55 +107,11 @@ namespace keepass2android.Io
|
|||||||
return new JavaFileStorageWriteTransaction(IocToPath(ioc), useFileTransaction, this);
|
return new JavaFileStorageWriteTransaction(IocToPath(ioc), useFileTransaction, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IFileStorageSetup RequiredSetup
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (Jfs.IsConnected)
|
|
||||||
return null;
|
|
||||||
return new JavaFileStorageSetup(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal IJavaFileStorage Jfs
|
internal IJavaFileStorage Jfs
|
||||||
{
|
{
|
||||||
get { return _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
|
class JavaFileStorageWriteTransaction: IWriteTransaction
|
||||||
{
|
{
|
||||||
@ -255,13 +215,14 @@ namespace keepass2android.Io
|
|||||||
CanWrite = e.CanWrite,
|
CanWrite = e.CanWrite,
|
||||||
IsDirectory = e.IsDirectory,
|
IsDirectory = e.IsDirectory,
|
||||||
LastModified = JavaTimeToCSharp(e.LastModifiedTime),
|
LastModified = JavaTimeToCSharp(e.LastModifiedTime),
|
||||||
Path = Protocol + "://" + e.Path,
|
Path = e.Path,
|
||||||
SizeInBytes = e.SizeInBytes
|
SizeInBytes = e.SizeInBytes
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileDescription GetFileDescription(IOConnectionInfo ioc)
|
public FileDescription GetFileDescription(IOConnectionInfo ioc)
|
||||||
{
|
{
|
||||||
|
Kp2aLog.Log("GetFileDescription "+ioc.Path);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return ConvertToFileDescription(Jfs.GetFileEntry(IocToPath(ioc)));
|
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)
|
private DateTime JavaTimeToCSharp(long javatime)
|
||||||
{
|
{
|
||||||
//todo test
|
|
||||||
return new DateTime(1970, 1, 1).AddMilliseconds(javatime);
|
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;
|
||||||
return ioc.Path.Substring(Protocol.Length + 3);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ioc.Path;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract string Protocol { get; }
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
@ -20,7 +20,7 @@
|
|||||||
<DebugType>full</DebugType>
|
<DebugType>full</DebugType>
|
||||||
<Optimize>false</Optimize>
|
<Optimize>false</Optimize>
|
||||||
<OutputPath>bin\Debug\</OutputPath>
|
<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>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@ -58,7 +58,10 @@
|
|||||||
<Compile Include="Io\BuiltInFileStorage.cs" />
|
<Compile Include="Io\BuiltInFileStorage.cs" />
|
||||||
<Compile Include="Io\CachingFileStorage.cs" />
|
<Compile Include="Io\CachingFileStorage.cs" />
|
||||||
<Compile Include="Io\DropboxFileStorage.cs" />
|
<Compile Include="Io\DropboxFileStorage.cs" />
|
||||||
|
<Compile Include="Io\DropboxFileStorageKeys.cs" />
|
||||||
<Compile Include="Io\FileDescription.cs" />
|
<Compile Include="Io\FileDescription.cs" />
|
||||||
|
<Compile Include="Io\FileStorageSetupActivity.cs" />
|
||||||
|
<Compile Include="Io\FileStorageSetupInitiatorActivity.cs" />
|
||||||
<Compile Include="Io\GDriveFileStorage.cs" />
|
<Compile Include="Io\GDriveFileStorage.cs" />
|
||||||
<Compile Include="Io\IFileStorage.cs" />
|
<Compile Include="Io\IFileStorage.cs" />
|
||||||
<Compile Include="Io\IoUtil.cs" />
|
<Compile Include="Io\IoUtil.cs" />
|
||||||
@ -93,7 +96,7 @@
|
|||||||
<Compile Include="ProgressDialogStatusLogger.cs" />
|
<Compile Include="ProgressDialogStatusLogger.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj" Condition="!$(DefineConstants.Contains('EXCLUDE_JAVAFILESTORAGE'))">
|
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj">
|
||||||
<Project>{48574278-4779-4b3a-a9e4-9cf1bc285d0b}</Project>
|
<Project>{48574278-4779-4b3a-a9e4-9cf1bc285d0b}</Project>
|
||||||
<Name>JavaFileStorageBindings</Name>
|
<Name>JavaFileStorageBindings</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
@ -5,5 +5,7 @@
|
|||||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
<classpathentry kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||||
|
<classpathentry kind="con" path="com.google.gdt.eclipse.managedapis.MANAGED_API_CONTAINER/drive-v2r102lv1.16.0-rc"/>
|
||||||
|
<classpathentry exported="true" kind="lib" path="C:/Users/Philipp/AppData/Local/Android/android-sdk/extras/google/google_play_services/libproject/google-play-services_lib/libs/google-play-services.jar"/>
|
||||||
<classpathentry kind="output" path="bin/classes"/>
|
<classpathentry kind="output" path="bin/classes"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
@ -18,5 +18,6 @@
|
|||||||
|
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@ -8,8 +8,9 @@
|
|||||||
# project structure.
|
# project structure.
|
||||||
#
|
#
|
||||||
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt:proguard-google-api-client.txt
|
||||||
|
|
||||||
# Project target.
|
# Project target.
|
||||||
target=android-17
|
target=android-17
|
||||||
android.library=true
|
android.library=true
|
||||||
|
android.library.reference.1=../../../../../../../AppData/Local/Android/android-sdk/extras/google/google_play_services/libproject/google-play-services_lib
|
||||||
|
@ -15,6 +15,7 @@ import android.content.SharedPreferences;
|
|||||||
import android.content.SharedPreferences.Editor;
|
import android.content.SharedPreferences.Editor;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.os.DropBoxManager.Entry;
|
import android.os.DropBoxManager.Entry;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
@ -35,7 +36,7 @@ import com.dropbox.client2.session.Session.AccessType;
|
|||||||
public class DropboxFileStorage implements JavaFileStorage {
|
public class DropboxFileStorage implements JavaFileStorage {
|
||||||
|
|
||||||
//NOTE: also adjust secret!
|
//NOTE: also adjust secret!
|
||||||
final static private String APP_KEY = "i8shu7v1hgh7ynt"; //KP2A
|
//final static private String APP_KEY = "i8shu7v1hgh7ynt"; //KP2A
|
||||||
//final static private String APP_KEY = "4ybka4p4a1027n6"; //FileStorageTest
|
//final static private String APP_KEY = "4ybka4p4a1027n6"; //FileStorageTest
|
||||||
|
|
||||||
// If you'd like to change the access type to the full Dropbox instead of
|
// If you'd like to change the access type to the full Dropbox instead of
|
||||||
@ -51,14 +52,36 @@ public class DropboxFileStorage implements JavaFileStorage {
|
|||||||
DropboxAPI<AndroidAuthSession> mApi;
|
DropboxAPI<AndroidAuthSession> mApi;
|
||||||
private boolean mLoggedIn = false;
|
private boolean mLoggedIn = false;
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
|
||||||
|
private String appKey;
|
||||||
|
private String appSecret;
|
||||||
|
|
||||||
public DropboxFileStorage(Context ctx)
|
public DropboxFileStorage(Context ctx, String _appKey, String _appSecret)
|
||||||
{
|
{
|
||||||
|
appKey = _appKey;
|
||||||
|
appSecret = _appSecret;
|
||||||
mContext = ctx;
|
mContext = ctx;
|
||||||
// We create a new AuthSession so that we can use the Dropbox API.
|
// We create a new AuthSession so that we can use the Dropbox API.
|
||||||
AndroidAuthSession session = buildSession();
|
AndroidAuthSession session = buildSession();
|
||||||
mApi = new DropboxAPI<AndroidAuthSession>(session);
|
mApi = new DropboxAPI<AndroidAuthSession>(session);
|
||||||
|
|
||||||
|
checkAppKeySetup();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DropboxFileStorage(Context ctx, String _appKey, String _appSecret, boolean clearKeysOnStart)
|
||||||
|
{
|
||||||
|
appKey = _appKey;
|
||||||
|
appSecret = _appSecret;
|
||||||
|
mContext = ctx;
|
||||||
|
|
||||||
|
if (clearKeysOnStart)
|
||||||
|
clearKeys();
|
||||||
|
|
||||||
|
|
||||||
|
// We create a new AuthSession so that we can use the Dropbox API.
|
||||||
|
AndroidAuthSession session = buildSession();
|
||||||
|
mApi = new DropboxAPI<AndroidAuthSession>(session);
|
||||||
|
|
||||||
checkAppKeySetup();
|
checkAppKeySetup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,29 +92,6 @@ public class DropboxFileStorage implements JavaFileStorage {
|
|||||||
return mLoggedIn;
|
return mLoggedIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onResume()
|
|
||||||
{
|
|
||||||
AndroidAuthSession session = mApi.getSession();
|
|
||||||
|
|
||||||
// The next part must be inserted in the onResume() method of the
|
|
||||||
// activity from which session.startAuthentication() was called, so
|
|
||||||
// that Dropbox authentication completes properly.
|
|
||||||
if (session.authenticationSuccessful()) {
|
|
||||||
try {
|
|
||||||
// Mandatory call to complete the auth
|
|
||||||
session.finishAuthentication();
|
|
||||||
|
|
||||||
// Store it locally in our app for later use
|
|
||||||
TokenPair tokens = session.getAccessTokenPair();
|
|
||||||
storeKeys(tokens.key, tokens.secret);
|
|
||||||
setLoggedIn(true);
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
Log.i(TAG, "Error authenticating", e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setLoggedIn(boolean b) {
|
private void setLoggedIn(boolean b) {
|
||||||
mLoggedIn = b;
|
mLoggedIn = b;
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ public class DropboxFileStorage implements JavaFileStorage {
|
|||||||
|
|
||||||
// Check if the app has set up its manifest properly.
|
// Check if the app has set up its manifest properly.
|
||||||
Intent testIntent = new Intent(Intent.ACTION_VIEW);
|
Intent testIntent = new Intent(Intent.ACTION_VIEW);
|
||||||
String scheme = "db-" + APP_KEY;
|
String scheme = "db-" + appKey;
|
||||||
String uri = scheme + "://" + AuthActivity.AUTH_VERSION + "/test";
|
String uri = scheme + "://" + AuthActivity.AUTH_VERSION + "/test";
|
||||||
testIntent.setData(Uri.parse(uri));
|
testIntent.setData(Uri.parse(uri));
|
||||||
PackageManager pm = mContext.getPackageManager();
|
PackageManager pm = mContext.getPackageManager();
|
||||||
@ -123,9 +123,10 @@ public class DropboxFileStorage implements JavaFileStorage {
|
|||||||
|
|
||||||
public boolean checkForFileChangeFast(String path, String previousFileVersion) throws Exception
|
public boolean checkForFileChangeFast(String path, String previousFileVersion) throws Exception
|
||||||
{
|
{
|
||||||
if ((previousFileVersion == null) || (previousFileVersion == ""))
|
if ((previousFileVersion == null) || (previousFileVersion.equals("")))
|
||||||
return false;
|
return false;
|
||||||
try {
|
try {
|
||||||
|
path = removeProtocol(path);
|
||||||
com.dropbox.client2.DropboxAPI.Entry entry = mApi.metadata(path, 1, null, false, null);
|
com.dropbox.client2.DropboxAPI.Entry entry = mApi.metadata(path, 1, null, false, null);
|
||||||
return entry.hash != previousFileVersion;
|
return entry.hash != previousFileVersion;
|
||||||
} catch (DropboxException e) {
|
} catch (DropboxException e) {
|
||||||
@ -136,6 +137,7 @@ public class DropboxFileStorage implements JavaFileStorage {
|
|||||||
public String getCurrentFileVersionFast(String path)
|
public String getCurrentFileVersionFast(String path)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
path = removeProtocol(path);
|
||||||
com.dropbox.client2.DropboxAPI.Entry entry = mApi.metadata(path, 1, null, false, null);
|
com.dropbox.client2.DropboxAPI.Entry entry = mApi.metadata(path, 1, null, false, null);
|
||||||
return entry.rev;
|
return entry.rev;
|
||||||
} catch (DropboxException e) {
|
} catch (DropboxException e) {
|
||||||
@ -147,6 +149,7 @@ public class DropboxFileStorage implements JavaFileStorage {
|
|||||||
public InputStream openFileForRead(String path) throws Exception
|
public InputStream openFileForRead(String path) throws Exception
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
path = removeProtocol(path);
|
||||||
return mApi.getFileStream(path, null);
|
return mApi.getFileStream(path, null);
|
||||||
} catch (DropboxException e) {
|
} catch (DropboxException e) {
|
||||||
//System.out.println("Something went wrong: " + e);
|
//System.out.println("Something went wrong: " + e);
|
||||||
@ -158,6 +161,7 @@ public class DropboxFileStorage implements JavaFileStorage {
|
|||||||
{
|
{
|
||||||
ByteArrayInputStream bis = new ByteArrayInputStream(data);
|
ByteArrayInputStream bis = new ByteArrayInputStream(data);
|
||||||
try {
|
try {
|
||||||
|
path = removeProtocol(path);
|
||||||
//TODO: it would be nice to be able to use the parent version with putFile()
|
//TODO: it would be nice to be able to use the parent version with putFile()
|
||||||
mApi.putFileOverwrite(path, bis, data.length, null);
|
mApi.putFileOverwrite(path, bis, data.length, null);
|
||||||
} catch (DropboxException e) {
|
} catch (DropboxException e) {
|
||||||
@ -231,7 +235,6 @@ public class DropboxFileStorage implements JavaFileStorage {
|
|||||||
edit.commit();
|
edit.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: call when Unlinked Exception
|
|
||||||
private void clearKeys() {
|
private void clearKeys() {
|
||||||
SharedPreferences prefs = mContext.getSharedPreferences(ACCOUNT_PREFS_NAME, 0);
|
SharedPreferences prefs = mContext.getSharedPreferences(ACCOUNT_PREFS_NAME, 0);
|
||||||
Editor edit = prefs.edit();
|
Editor edit = prefs.edit();
|
||||||
@ -240,8 +243,7 @@ public class DropboxFileStorage implements JavaFileStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private AndroidAuthSession buildSession() {
|
private AndroidAuthSession buildSession() {
|
||||||
//note: the SecretKeys class is not public because the App-Secret must be secret!
|
AppKeyPair appKeyPair = new AppKeyPair(appKey, appSecret);
|
||||||
AppKeyPair appKeyPair = new AppKeyPair(APP_KEY, SecretKeys.DROPBOX_APP_SECRET);
|
|
||||||
AndroidAuthSession session;
|
AndroidAuthSession session;
|
||||||
|
|
||||||
String[] stored = getKeys();
|
String[] stored = getKeys();
|
||||||
@ -263,6 +265,7 @@ public class DropboxFileStorage implements JavaFileStorage {
|
|||||||
public void createFolder(String path) throws Exception {
|
public void createFolder(String path) throws Exception {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
path = removeProtocol(path);
|
||||||
mApi.createFolder(path);
|
mApi.createFolder(path);
|
||||||
}
|
}
|
||||||
catch (DropboxException e) {
|
catch (DropboxException e) {
|
||||||
@ -274,6 +277,7 @@ public class DropboxFileStorage implements JavaFileStorage {
|
|||||||
public List<FileEntry> listFiles(String dirName) throws Exception {
|
public List<FileEntry> listFiles(String dirName) throws Exception {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
dirName = removeProtocol(dirName);
|
||||||
com.dropbox.client2.DropboxAPI.Entry dirEntry = mApi.metadata(dirName, 0, null, true, null);
|
com.dropbox.client2.DropboxAPI.Entry dirEntry = mApi.metadata(dirName, 0, null, true, null);
|
||||||
|
|
||||||
if (dirEntry.isDeleted)
|
if (dirEntry.isDeleted)
|
||||||
@ -305,7 +309,7 @@ public class DropboxFileStorage implements JavaFileStorage {
|
|||||||
fileEntry.canWrite = true;
|
fileEntry.canWrite = true;
|
||||||
fileEntry.isDirectory = e.isDir;
|
fileEntry.isDirectory = e.isDir;
|
||||||
fileEntry.sizeInBytes = e.bytes;
|
fileEntry.sizeInBytes = e.bytes;
|
||||||
fileEntry.path = e.path;
|
fileEntry.path = getProtocolId()+"://"+ e.path;
|
||||||
//Log.d("JFS","fileEntry="+fileEntry);
|
//Log.d("JFS","fileEntry="+fileEntry);
|
||||||
Date lastModifiedDate = null;
|
Date lastModifiedDate = null;
|
||||||
if (e.modified != null)
|
if (e.modified != null)
|
||||||
@ -322,6 +326,7 @@ public class DropboxFileStorage implements JavaFileStorage {
|
|||||||
public void delete(String path) throws Exception {
|
public void delete(String path) throws Exception {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
path = removeProtocol(path);
|
||||||
mApi.delete(path);
|
mApi.delete(path);
|
||||||
} catch (DropboxException e) {
|
} catch (DropboxException e) {
|
||||||
throw convertException(e);
|
throw convertException(e);
|
||||||
@ -334,8 +339,8 @@ public class DropboxFileStorage implements JavaFileStorage {
|
|||||||
public FileEntry getFileEntry(String filename) throws Exception {
|
public FileEntry getFileEntry(String filename) throws Exception {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Log.d("JFS", "Hi!");
|
filename = removeProtocol(filename);
|
||||||
Log.d("JFS", "mApi = "+mApi);
|
Log.d("KP2AJ", "getFileEntry(), mApi = "+mApi+" filename="+filename);
|
||||||
com.dropbox.client2.DropboxAPI.Entry dbEntry = mApi.metadata(filename, 0, null, false, null);
|
com.dropbox.client2.DropboxAPI.Entry dbEntry = mApi.metadata(filename, 0, null, false, null);
|
||||||
Log.d("JFS", "dbEntry = "+dbEntry);
|
Log.d("JFS", "dbEntry = "+dbEntry);
|
||||||
|
|
||||||
@ -350,4 +355,164 @@ public class DropboxFileStorage implements JavaFileStorage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startSelectFile(FileStorageSetupInitiatorActivity activity, boolean isForSave,
|
||||||
|
int requestCode)
|
||||||
|
{
|
||||||
|
|
||||||
|
String path = getProtocolId()+":///";
|
||||||
|
Log.d("KP2AJ", "startSelectFile "+path+", connected: "+path);
|
||||||
|
if (isConnected())
|
||||||
|
{
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.putExtra(EXTRA_IS_FOR_SAVE, isForSave);
|
||||||
|
intent.putExtra(EXTRA_PATH, path);
|
||||||
|
activity.onImmediateResult(requestCode, RESULT_FILECHOOSER_PREPARED, intent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
activity.startSelectFileProcess(path, isForSave, requestCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getProtocolId() {
|
||||||
|
return "dropbox";
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean requiresSetup(String path)
|
||||||
|
{
|
||||||
|
return !isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void prepareFileUsage(FileStorageSetupInitiatorActivity activity, String path, int requestCode) {
|
||||||
|
if (isConnected())
|
||||||
|
{
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.putExtra(EXTRA_PATH, path);
|
||||||
|
activity.onImmediateResult(requestCode, RESULT_FILEUSAGE_PREPARED, intent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
activity.startFileUsageProcess(path, requestCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(FileStorageSetupActivity activity, Bundle savedInstanceState) {
|
||||||
|
|
||||||
|
Log.d("KP2AJ", "OnCreate");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume(FileStorageSetupActivity activity) {
|
||||||
|
|
||||||
|
Log.d("KP2AJ", "OnResume. LoggedIn="+mLoggedIn);
|
||||||
|
if (mLoggedIn)
|
||||||
|
{
|
||||||
|
finishActivityWithSuccess(activity);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AndroidAuthSession session = mApi.getSession();
|
||||||
|
|
||||||
|
// The next part must be inserted in the onResume() method of the
|
||||||
|
// activity from which session.startAuthentication() was called, so
|
||||||
|
// that Dropbox authentication completes properly.
|
||||||
|
if (session.authenticationSuccessful()) {
|
||||||
|
try {
|
||||||
|
// Mandatory call to complete the auth
|
||||||
|
session.finishAuthentication();
|
||||||
|
|
||||||
|
// Store it locally in our app for later use
|
||||||
|
TokenPair tokens = session.getAccessTokenPair();
|
||||||
|
storeKeys(tokens.key, tokens.secret);
|
||||||
|
setLoggedIn(true);
|
||||||
|
|
||||||
|
finishActivityWithSuccess(activity);
|
||||||
|
return;
|
||||||
|
|
||||||
|
} catch (Throwable t) {
|
||||||
|
Log.i(TAG, "Error authenticating", t);
|
||||||
|
Intent data = new Intent();
|
||||||
|
data.putExtra(EXTRA_ERROR_MESSAGE, t.getMessage());
|
||||||
|
((Activity)activity).setResult(Activity.RESULT_CANCELED, data);
|
||||||
|
((Activity)activity).finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JavaFileStorage.FileStorageSetupActivity storageSetupAct = (JavaFileStorage.FileStorageSetupActivity)activity;
|
||||||
|
|
||||||
|
if (storageSetupAct.getState().containsKey("hasStartedAuth"))
|
||||||
|
{
|
||||||
|
Log.i(TAG, "authenticating not succesful");
|
||||||
|
Intent data = new Intent();
|
||||||
|
data.putExtra(EXTRA_ERROR_MESSAGE, "authenticating not succesful");
|
||||||
|
((Activity)activity).setResult(Activity.RESULT_CANCELED, data);
|
||||||
|
((Activity)activity).finish();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.d("KP2AJ", "Starting auth");
|
||||||
|
mApi.getSession().startAuthentication(((Activity)activity));
|
||||||
|
storageSetupAct.getState().putBoolean("hasStartedAuth", true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void finishActivityWithSuccess(FileStorageSetupActivity setupActivity) {
|
||||||
|
Log.d("KP2AJ", "Success with authentcating!");
|
||||||
|
Activity activity = (Activity)setupActivity;
|
||||||
|
|
||||||
|
if (setupActivity.getProcessName().equals(PROCESS_NAME_FILE_USAGE_SETUP))
|
||||||
|
{
|
||||||
|
Intent data = new Intent();
|
||||||
|
data.putExtra(EXTRA_IS_FOR_SAVE, setupActivity.isForSave());
|
||||||
|
data.putExtra(EXTRA_PATH, setupActivity.getPath());
|
||||||
|
activity.setResult(RESULT_FILEUSAGE_PREPARED, data);
|
||||||
|
activity.finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (setupActivity.getProcessName().equals(PROCESS_NAME_SELECTFILE))
|
||||||
|
{
|
||||||
|
Intent data = new Intent();
|
||||||
|
data.putExtra(EXTRA_PATH, setupActivity.getPath());
|
||||||
|
activity.setResult(RESULT_FILECHOOSER_PREPARED, data);
|
||||||
|
activity.finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.w("KP2AJ", "Unknown process: " + setupActivity.getProcessName());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart(FileStorageSetupActivity activity) {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(FileStorageSetupActivity activity, int requestCode, int resultCode, Intent data) {
|
||||||
|
//nothing to do here
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
String removeProtocol(String path)
|
||||||
|
{
|
||||||
|
if (path == null)
|
||||||
|
return null;
|
||||||
|
return path.substring(getProtocolId().length()+3);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,262 @@
|
|||||||
|
package keepass2android.javafilestorage;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.google.api.client.extensions.android.http.AndroidHttp;
|
||||||
|
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
|
||||||
|
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException;
|
||||||
|
import com.google.api.client.json.gson.GsonFactory;
|
||||||
|
import com.google.api.services.drive.Drive;
|
||||||
|
import com.google.api.services.drive.Drive.Children;
|
||||||
|
import com.google.api.services.drive.DriveScopes;
|
||||||
|
import com.google.api.services.drive.model.ChildList;
|
||||||
|
import com.google.api.services.drive.model.ChildReference;
|
||||||
|
|
||||||
|
import android.accounts.AccountManager;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
|
public class GoogleDriveFileStorage
|
||||||
|
{};
|
||||||
|
/*/
|
||||||
|
public class GoogleDriveFileStorage implements JavaFileStorage {
|
||||||
|
|
||||||
|
private static Drive service;
|
||||||
|
//private GoogleAccountCredential credential;
|
||||||
|
|
||||||
|
static final int MAGIC_GDRIVE=2082334;
|
||||||
|
static final int REQUEST_ACCOUNT_PICKER = MAGIC_GDRIVE+1;
|
||||||
|
static final int REQUEST_AUTHORIZATION = MAGIC_GDRIVE+2;
|
||||||
|
|
||||||
|
class TestConnectionTask extends AsyncTask<Object, Void, Void>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Object... params) {
|
||||||
|
|
||||||
|
Activity activity = (Activity) params[0];
|
||||||
|
|
||||||
|
//try to list files:
|
||||||
|
//todo: is there a simpler way to test if the user is authorized?
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (UserRecoverableAuthIOException e) {
|
||||||
|
activity.startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
Intent data = new Intent();
|
||||||
|
data.putExtra(EXTRA_ERROR_MESSAGE, t.getMessage());
|
||||||
|
activity.setResult(Activity.RESULT_CANCELED, data);
|
||||||
|
activity.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void printFilesInFolder(Drive service, String folderId)
|
||||||
|
throws IOException {
|
||||||
|
Children.List request = service.files().list();
|
||||||
|
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
ChildList children = request.execute();
|
||||||
|
|
||||||
|
for (ChildReference child : children.getItems()) {
|
||||||
|
System.out.println("File Id: " + child.getId());
|
||||||
|
}
|
||||||
|
request.setPageToken(children.getNextPageToken());
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("An error occurred: " + e);
|
||||||
|
request.setPageToken(null);
|
||||||
|
}
|
||||||
|
} while (request.getPageToken() != null &&
|
||||||
|
request.getPageToken().length() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean tryConnect(Activity activity) {
|
||||||
|
|
||||||
|
List<String> scopes = new ArrayList<String>();
|
||||||
|
scopes.add(DriveScopes.DRIVE);
|
||||||
|
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(activity, scopes);
|
||||||
|
|
||||||
|
String storedAccountName = PreferenceManager.getDefaultSharedPreferences(activity).getString("GDRIVE_ACCOUNT_NAME", null);
|
||||||
|
|
||||||
|
if (storedAccountName != null)
|
||||||
|
{
|
||||||
|
credential.setSelectedAccountName(storedAccountName);
|
||||||
|
//try to list files:
|
||||||
|
//todo: is there a simpler way to test if the user is authorized?
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (UserRecoverableAuthIOException e) {
|
||||||
|
activity.startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
activity.startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkForFileChangeFast(String path,
|
||||||
|
String previousFileVersion) throws Exception {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCurrentFileVersionFast(String path) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream openFileForRead(String path) throws Exception {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void uploadFile(String path, byte[] data, boolean writeTransactional)
|
||||||
|
throws Exception {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createFolder(String path) throws Exception {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<FileEntry> listFiles(String dirName) throws Exception {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileEntry getFileEntry(String filename) throws Exception {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(String path) throws Exception {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Drive getDriveService(GoogleAccountCredential credential) {
|
||||||
|
return new Drive.Builder(AndroidHttp.newCompatibleTransport(), new GsonFactory(), credential)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
|
||||||
|
switch (requestCode) {
|
||||||
|
case REQUEST_ACCOUNT_PICKER:
|
||||||
|
|
||||||
|
if (resultCode == Activity.RESULT_OK && data != null && data.getExtras() != null) {
|
||||||
|
String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
|
||||||
|
if (accountName != null) {
|
||||||
|
//credential.setSelectedAccountName(accountName);
|
||||||
|
todo
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
todo
|
||||||
|
|
||||||
|
case REQUEST_AUTHORIZATION:
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
// App is authorized
|
||||||
|
todo
|
||||||
|
} else {
|
||||||
|
// User denied access, show him the account chooser again
|
||||||
|
activity.startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startSelectFile(Activity activity, boolean isForSave,
|
||||||
|
int requestCode) {
|
||||||
|
((JavaFileStorage.FileStorageSetupInitiatorActivity)(activity)).startSelectFileProcess(getProtocolId()+"://", isForSave, requestCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void prepareFileUsage(Activity activity, String path, int requestCode) {
|
||||||
|
((JavaFileStorage.FileStorageSetupInitiatorActivity)(activity)).startFileUsageProcess(path, requestCode);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getProtocolId() {
|
||||||
|
|
||||||
|
return "gdrive";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume(Activity activity) {
|
||||||
|
|
||||||
|
JavaFileStorage.FileStorageSetupActivity setupAct = (FileStorageSetupActivity) activity;
|
||||||
|
|
||||||
|
if (activity.isFinishing())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!hasAccount(setupAct))
|
||||||
|
{
|
||||||
|
List<String> scopes = new ArrayList<String>();
|
||||||
|
scopes.add(DriveScopes.DRIVE);
|
||||||
|
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(activity, scopes);
|
||||||
|
|
||||||
|
activity.startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart(Activity activity) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
@ -4,9 +4,37 @@ import java.io.InputStream;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
public interface JavaFileStorage {
|
public interface JavaFileStorage {
|
||||||
|
|
||||||
|
public static final String PROCESS_NAME_SELECTFILE = "SELECT_FILE";
|
||||||
|
public static final String PROCESS_NAME_FILE_USAGE_SETUP = "FILE_USAGE_SETUP";
|
||||||
|
|
||||||
|
public static final String EXTRA_PROCESS_NAME = "EXTRA_PROCESS_NAME";
|
||||||
|
public static final String EXTRA_PATH = "fileName"; //match KP2A PasswordActivity Ioc-Path Extra key
|
||||||
|
public static final String EXTRA_IS_FOR_SAVE = "IS_FOR_SAVE";
|
||||||
|
public static final String EXTRA_ERROR_MESSAGE = "EXTRA_ERROR_MESSAGE";
|
||||||
|
|
||||||
|
|
||||||
|
public interface FileStorageSetupInitiatorActivity
|
||||||
|
{
|
||||||
|
void startSelectFileProcess(String path, boolean isForSave, int requestCode);
|
||||||
|
void startFileUsageProcess(String path, int requestCode);
|
||||||
|
void onImmediateResult(int requestCode, int result, Intent intent);
|
||||||
|
Activity getActivity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface FileStorageSetupActivity
|
||||||
|
{
|
||||||
|
String getPath();
|
||||||
|
String getProcessName();
|
||||||
|
//int getRequestCode();
|
||||||
|
boolean isForSave();
|
||||||
|
Bundle getState();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public class FileEntry {
|
public class FileEntry {
|
||||||
public String path;
|
public String path;
|
||||||
@ -66,11 +94,26 @@ public class FileEntry {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean tryConnect(Activity activity);
|
//public boolean tryConnect(Activity activity);
|
||||||
|
|
||||||
public void onResume();
|
//public void onResume();
|
||||||
|
|
||||||
|
//public void onActivityResult(Activity activity, final int requestCode, final int resultCode, final Intent data);
|
||||||
|
|
||||||
public boolean isConnected();
|
//public boolean isConnected();
|
||||||
|
|
||||||
|
public static int MAGIC_NUMBER_JFS = 874345;
|
||||||
|
public static int RESULT_FULL_FILENAME_SELECTED = MAGIC_NUMBER_JFS+1;
|
||||||
|
public static int RESULT_FILECHOOSER_PREPARED = MAGIC_NUMBER_JFS+2;
|
||||||
|
public static int RESULT_FILEUSAGE_PREPARED = MAGIC_NUMBER_JFS+3;
|
||||||
|
|
||||||
|
public boolean requiresSetup(String path);
|
||||||
|
|
||||||
|
public void startSelectFile(FileStorageSetupInitiatorActivity activity, boolean isForSave, int requestCode);
|
||||||
|
|
||||||
|
public void prepareFileUsage(FileStorageSetupInitiatorActivity activity, String path, int requestCode);
|
||||||
|
|
||||||
|
public String getProtocolId();
|
||||||
|
|
||||||
public boolean checkForFileChangeFast(String path, String previousFileVersion) throws Exception;
|
public boolean checkForFileChangeFast(String path, String previousFileVersion) throws Exception;
|
||||||
|
|
||||||
@ -88,4 +131,9 @@ public class FileEntry {
|
|||||||
|
|
||||||
public void delete(String path) throws Exception;
|
public void delete(String path) throws Exception;
|
||||||
|
|
||||||
|
public void onCreate(FileStorageSetupActivity activity, Bundle savedInstanceState);
|
||||||
|
public void onResume(FileStorageSetupActivity activity);
|
||||||
|
public void onStart(FileStorageSetupActivity activity);
|
||||||
|
public void onActivityResult(FileStorageSetupActivity activity, int requestCode, int resultCode, Intent data);
|
||||||
|
|
||||||
}
|
}
|
@ -980,11 +980,14 @@ public class FragmentFiles extends Fragment implements
|
|||||||
|
|
||||||
if (path == null
|
if (path == null
|
||||||
|| !BaseFileProviderUtils.isDirectory(getActivity(), path))
|
|| !BaseFileProviderUtils.isDirectory(getActivity(), path))
|
||||||
|
{
|
||||||
|
Log.d(CLASSNAME, "load default path");
|
||||||
path = BaseFileProviderUtils
|
path = BaseFileProviderUtils
|
||||||
.getDefaultPath(
|
.getDefaultPath(
|
||||||
getActivity(),
|
getActivity(),
|
||||||
path == null ? mFileProviderAuthority : path
|
path == null ? mFileProviderAuthority : path
|
||||||
.getAuthority());
|
.getAuthority());
|
||||||
|
}
|
||||||
|
|
||||||
if (path == null) {
|
if (path == null) {
|
||||||
showCannotConnectToServiceAndFinish();
|
showCannotConnectToServiceAndFinish();
|
||||||
|
@ -213,10 +213,7 @@ public class DisplayPrefs extends Prefs {
|
|||||||
* @since v4.7 beta
|
* @since v4.7 beta
|
||||||
*/
|
*/
|
||||||
public static boolean isRememberLastLocation(Context c) {
|
public static boolean isRememberLastLocation(Context c) {
|
||||||
return p(c).getBoolean(
|
return false; //KP2A: don't allow to remember because of different protocols
|
||||||
c.getString(R.string.afc_pkey_display_remember_last_location),
|
|
||||||
c.getResources().getBoolean(
|
|
||||||
R.bool.afc_pkey_display_remember_last_location_def));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,7 +13,7 @@ public class Kp2aFileChooserBridge {
|
|||||||
Class<?> cls = FileChooserActivity.class;
|
Class<?> cls = FileChooserActivity.class;
|
||||||
|
|
||||||
Intent intent = new Intent(ctx, cls);
|
Intent intent = new Intent(ctx, cls);
|
||||||
|
intent.putExtra(FileChooserActivity.EXTRA_FILE_PROVIDER_AUTHORITY, authority);
|
||||||
intent.putExtra(FileChooserActivity.EXTRA_ROOTPATH,
|
intent.putExtra(FileChooserActivity.EXTRA_ROOTPATH,
|
||||||
BaseFile.genContentIdUriBase(authority)
|
BaseFile.genContentIdUriBase(authority)
|
||||||
.buildUpon()
|
.buildUpon()
|
||||||
|
@ -230,7 +230,11 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
|
|||||||
private MatrixCursor doAnswerApiCommand(Uri uri) {
|
private MatrixCursor doAnswerApiCommand(Uri uri) {
|
||||||
MatrixCursor matrixCursor = null;
|
MatrixCursor matrixCursor = null;
|
||||||
|
|
||||||
if (BaseFile.CMD_CANCEL.equals(uri.getLastPathSegment())) {
|
String lastPathSegment = uri.getLastPathSegment();
|
||||||
|
|
||||||
|
//Log.d(CLASSNAME, "lastPathSegment:" + lastPathSegment);
|
||||||
|
|
||||||
|
if (BaseFile.CMD_CANCEL.equals(lastPathSegment)) {
|
||||||
int taskId = ProviderUtils.getIntQueryParam(uri,
|
int taskId = ProviderUtils.getIntQueryParam(uri,
|
||||||
BaseFile.PARAM_TASK_ID, 0);
|
BaseFile.PARAM_TASK_ID, 0);
|
||||||
synchronized (mMapInterruption) {
|
synchronized (mMapInterruption) {
|
||||||
@ -241,15 +245,14 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
|
|||||||
mMapInterruption.put(taskId, true);
|
mMapInterruption.put(taskId, true);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
} else if (BaseFile.CMD_GET_DEFAULT_PATH.equals(uri
|
} else if (BaseFile.CMD_GET_DEFAULT_PATH.equals(lastPathSegment)) {
|
||||||
.getLastPathSegment())) {
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}// get default path
|
}// get default path
|
||||||
else if (BaseFile.CMD_IS_ANCESTOR_OF.equals(uri.getLastPathSegment())) {
|
else if (BaseFile.CMD_IS_ANCESTOR_OF.equals(lastPathSegment)) {
|
||||||
return doCheckAncestor(uri);
|
return doCheckAncestor(uri);
|
||||||
} else if (BaseFile.CMD_GET_PARENT.equals(uri.getLastPathSegment())) {
|
} else if (BaseFile.CMD_GET_PARENT.equals(lastPathSegment)) {
|
||||||
|
|
||||||
{
|
{
|
||||||
String path = Uri.parse(
|
String path = Uri.parse(
|
||||||
@ -292,7 +295,7 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
|
|||||||
return matrixCursor;
|
return matrixCursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (BaseFile.CMD_SHUTDOWN.equals(uri.getLastPathSegment())) {
|
} else if (BaseFile.CMD_SHUTDOWN.equals(lastPathSegment)) {
|
||||||
/*
|
/*
|
||||||
* TODO Stop all tasks. If the activity call this command in
|
* TODO Stop all tasks. If the activity call this command in
|
||||||
* onDestroy(), it seems that this code block will be suspended and
|
* onDestroy(), it seems that this code block will be suspended and
|
||||||
@ -492,7 +495,8 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
|
|||||||
|
|
||||||
//puts the file entry in the cache for later reuse with retrieveFileInfo
|
//puts the file entry in the cache for later reuse with retrieveFileInfo
|
||||||
private void updateFileEntryCache(FileEntry f) {
|
private void updateFileEntryCache(FileEntry f) {
|
||||||
fileEntryMap.put(f.path, f);
|
if (f != null)
|
||||||
|
fileEntryMap.put(f.path, f);
|
||||||
}
|
}
|
||||||
//removes the file entry from the cache (if cached). Should be called whenever the file changes
|
//removes the file entry from the cache (if cached). Should be called whenever the file changes
|
||||||
private void removeFromCache(String filename, boolean recursive) {
|
private void removeFromCache(String filename, boolean recursive) {
|
||||||
@ -501,11 +505,17 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
|
|||||||
if (recursive)
|
if (recursive)
|
||||||
{
|
{
|
||||||
Set<String> keys = fileEntryMap.keySet();
|
Set<String> keys = fileEntryMap.keySet();
|
||||||
|
Set<String> keysToRemove = new HashSet<String>();
|
||||||
for (String key: keys)
|
for (String key: keys)
|
||||||
{
|
{
|
||||||
if (key.startsWith(key))
|
if (key.startsWith(key))
|
||||||
fileEntryMap.remove(key);
|
keysToRemove.add(key);
|
||||||
}
|
}
|
||||||
|
for (String key: keysToRemove)
|
||||||
|
{
|
||||||
|
fileEntryMap.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ namespace keepass2android
|
|||||||
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
|
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
|
||||||
builder.SetTitle(ctx.GetString(Resource.String.ChangeLog_title));
|
builder.SetTitle(ctx.GetString(Resource.String.ChangeLog_title));
|
||||||
String[] changeLog = {
|
String[] changeLog = {
|
||||||
|
ctx.GetString(Resource.String.ChangeLog_0_9),
|
||||||
ctx.GetString(Resource.String.ChangeLog_0_8_6),
|
ctx.GetString(Resource.String.ChangeLog_0_8_6),
|
||||||
ctx.GetString(Resource.String.ChangeLog_0_8_5),
|
ctx.GetString(Resource.String.ChangeLog_0_8_5),
|
||||||
ctx.GetString(Resource.String.ChangeLog_0_8_4),
|
ctx.GetString(Resource.String.ChangeLog_0_8_4),
|
||||||
|
@ -1,20 +1,10 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
using Android.App;
|
using Android.App;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
using Android.Content.PM;
|
using Android.Content.PM;
|
||||||
using Android.Graphics.Drawables;
|
|
||||||
using Android.OS;
|
using Android.OS;
|
||||||
using Android.Runtime;
|
|
||||||
using Android.Views;
|
using Android.Views;
|
||||||
using Android.Widget;
|
using Android.Widget;
|
||||||
using KeePassLib;
|
|
||||||
using KeePassLib.Keys;
|
|
||||||
using KeePassLib.Security;
|
|
||||||
using KeePassLib.Serialization;
|
|
||||||
using keepass2android.Io;
|
using keepass2android.Io;
|
||||||
using keepass2android.view;
|
using keepass2android.view;
|
||||||
using Object = Java.Lang.Object;
|
using Object = Java.Lang.Object;
|
||||||
@ -24,15 +14,17 @@ namespace keepass2android
|
|||||||
[Activity (Label = "@string/app_name", ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden , Theme="@style/NoTitleBar")]
|
[Activity (Label = "@string/app_name", ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden , Theme="@style/NoTitleBar")]
|
||||||
public class FileStorageSelectionActivity : ListActivity
|
public class FileStorageSelectionActivity : ListActivity
|
||||||
{
|
{
|
||||||
private string _protocolToSetup;
|
|
||||||
private FileStorageAdapter _fileStorageAdapter;
|
private FileStorageAdapter _fileStorageAdapter;
|
||||||
|
|
||||||
|
public const string AllowThirdPartyAppGet = "AllowThirdPartyAppGet";
|
||||||
|
public const string AllowThirdPartyAppSend = "AllowThirdPartyAppSend";
|
||||||
|
|
||||||
class FileStorageAdapter: BaseAdapter
|
class FileStorageAdapter: BaseAdapter
|
||||||
{
|
{
|
||||||
|
|
||||||
private readonly FileStorageSelectionActivity _context;
|
private readonly FileStorageSelectionActivity _context;
|
||||||
|
|
||||||
private List<string> _protocolIds = new List<string>();
|
private readonly List<string> _protocolIds = new List<string>();
|
||||||
|
|
||||||
public FileStorageAdapter(FileStorageSelectionActivity context)
|
public FileStorageAdapter(FileStorageSelectionActivity context)
|
||||||
{
|
{
|
||||||
@ -40,8 +32,13 @@ namespace keepass2android
|
|||||||
//show all supported protocols:
|
//show all supported protocols:
|
||||||
foreach (IFileStorage fs in App.Kp2a.FileStorages)
|
foreach (IFileStorage fs in App.Kp2a.FileStorages)
|
||||||
_protocolIds.AddRange(fs.SupportedProtocols);
|
_protocolIds.AddRange(fs.SupportedProtocols);
|
||||||
//except file://
|
//put file:// to the top
|
||||||
_protocolIds.Remove("file");
|
_protocolIds.Remove("file");
|
||||||
|
_protocolIds.Insert(0, "file");
|
||||||
|
if (context.Intent.GetBooleanExtra(AllowThirdPartyAppGet, false))
|
||||||
|
_protocolIds.Add("androidget");
|
||||||
|
if (context.Intent.GetBooleanExtra(AllowThirdPartyAppSend, false))
|
||||||
|
_protocolIds.Add("androidsend");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Object GetItem(int position)
|
public override Object GetItem(int position)
|
||||||
@ -69,24 +66,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
private void OnItemSelected(string protocolId)
|
private void OnItemSelected(string protocolId)
|
||||||
{
|
{
|
||||||
var fs = App.Kp2a.GetFileStorage(protocolId);
|
ReturnProtocol(protocolId);
|
||||||
IFileStorageSetup fssetup = fs.RequiredSetup;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if ((fssetup == null) || (fssetup.TrySetup(this)))
|
|
||||||
{
|
|
||||||
ReturnProtocol(protocolId);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//setup not yet complete
|
|
||||||
_protocolToSetup = protocolId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Toast.MakeText(this, e.Message, ToastLength.Long).Show();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,46 +82,16 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
base.OnCreate(bundle);
|
base.OnCreate(bundle);
|
||||||
|
|
||||||
if (bundle != null)
|
|
||||||
_protocolToSetup = bundle.GetString("_protocolToSetup", null);
|
|
||||||
|
|
||||||
SetContentView(Resource.Layout.filestorage_selection);
|
SetContentView(Resource.Layout.filestorage_selection);
|
||||||
|
|
||||||
_fileStorageAdapter = new FileStorageAdapter(this);
|
_fileStorageAdapter = new FileStorageAdapter(this);
|
||||||
this.ListAdapter = _fileStorageAdapter;
|
ListAdapter = _fileStorageAdapter;
|
||||||
|
|
||||||
FindViewById<ListView>(Android.Resource.Id.List).ItemClick +=
|
FindViewById<ListView>(Android.Resource.Id.List).ItemClick +=
|
||||||
(sender, args) => OnItemSelected((string)_fileStorageAdapter.GetItem(args.Position));
|
(sender, args) => OnItemSelected((string)_fileStorageAdapter.GetItem(args.Position));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSaveInstanceState(Bundle outState)
|
|
||||||
{
|
|
||||||
base.OnSaveInstanceState(outState);
|
|
||||||
outState.PutString("_protocolToSetup",_protocolToSetup);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnResume()
|
|
||||||
{
|
|
||||||
base.OnResume();
|
|
||||||
if (!String.IsNullOrEmpty(_protocolToSetup))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string protocolToSetup = _protocolToSetup;
|
|
||||||
_protocolToSetup = null;
|
|
||||||
|
|
||||||
IFileStorageSetupOnResume fsSetup = App.Kp2a.GetFileStorage(protocolToSetup).RequiredSetup as IFileStorageSetupOnResume;
|
|
||||||
if ((fsSetup == null) || (fsSetup.TrySetupOnResume(this)))
|
|
||||||
{
|
|
||||||
ReturnProtocol(protocolToSetup);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Toast.MakeText(this, e.Message, ToastLength.Long).Show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -31,7 +31,7 @@ using Android.Content.PM;
|
|||||||
using KeePassLib.Keys;
|
using KeePassLib.Keys;
|
||||||
using KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
using KeePassLib.Utility;
|
using KeePassLib.Utility;
|
||||||
|
using keepass2android.Io;
|
||||||
using MemoryStream = System.IO.MemoryStream;
|
using MemoryStream = System.IO.MemoryStream;
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
@ -189,6 +189,9 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case (Result)FileStorageResults.FileUsagePrepared:
|
||||||
|
PeformLoadDatabase();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -272,26 +275,11 @@ namespace keepass2android
|
|||||||
Window.SetSoftInputMode(SoftInput.StateVisible);
|
Window.SetSoftInputMode(SoftInput.StateVisible);
|
||||||
|
|
||||||
Button confirmButton = (Button)FindViewById(Resource.Id.pass_ok);
|
Button confirmButton = (Button)FindViewById(Resource.Id.pass_ok);
|
||||||
confirmButton.Click += (sender, e) => {
|
confirmButton.Click += (sender, e) =>
|
||||||
String pass = GetEditText(Resource.Id.password);
|
|
||||||
String key = GetEditText(Resource.Id.pass_keyfile);
|
|
||||||
if (pass.Length == 0 && key.Length == 0)
|
|
||||||
{
|
{
|
||||||
ErrorMessage(Resource.String.error_nopass);
|
App.Kp2a.GetFileStorage(_ioConnection)
|
||||||
return;
|
.PrepareFileUsage(new FileStorageSetupInitiatorActivity(this, OnActivityResult), _ioConnection, 0);
|
||||||
}
|
};
|
||||||
|
|
||||||
CheckBox cbQuickUnlock = (CheckBox)FindViewById(Resource.Id.enable_quickunlock);
|
|
||||||
App.Kp2a.SetQuickUnlockEnabled(cbQuickUnlock.Checked);
|
|
||||||
|
|
||||||
Handler handler = new Handler();
|
|
||||||
LoadDb task = new LoadDb(App.Kp2a, _ioConnection, _loadDbTask, pass, key, new AfterLoad(handler, this));
|
|
||||||
_loadDbTask = null; // prevent accidental re-use
|
|
||||||
|
|
||||||
SetNewDefaultFile();
|
|
||||||
|
|
||||||
new ProgressTask(App.Kp2a, this, task).Run();
|
|
||||||
};
|
|
||||||
|
|
||||||
/*CheckBox checkBox = (CheckBox) FindViewById(Resource.Id.show_password);
|
/*CheckBox checkBox = (CheckBox) FindViewById(Resource.Id.show_password);
|
||||||
// Show or hide password
|
// Show or hide password
|
||||||
@ -334,6 +322,32 @@ namespace keepass2android
|
|||||||
RetrieveSettings();
|
RetrieveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void PeformLoadDatabase()
|
||||||
|
{
|
||||||
|
String pass = GetEditText(Resource.Id.password);
|
||||||
|
String key = GetEditText(Resource.Id.pass_keyfile);
|
||||||
|
if (pass.Length == 0 && key.Length == 0)
|
||||||
|
{
|
||||||
|
ErrorMessage(Resource.String.error_nopass);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox cbQuickUnlock = (CheckBox) FindViewById(Resource.Id.enable_quickunlock);
|
||||||
|
App.Kp2a.SetQuickUnlockEnabled(cbQuickUnlock.Checked);
|
||||||
|
|
||||||
|
//avoid password being visible while loading:
|
||||||
|
_showPassword = false;
|
||||||
|
MakePasswordMaskedOrVisible();
|
||||||
|
|
||||||
|
Handler handler = new Handler();
|
||||||
|
LoadDb task = new LoadDb(App.Kp2a, _ioConnection, _loadDbTask, pass, key, new AfterLoad(handler, this));
|
||||||
|
_loadDbTask = null; // prevent accidental re-use
|
||||||
|
|
||||||
|
SetNewDefaultFile();
|
||||||
|
|
||||||
|
new ProgressTask(App.Kp2a, this, task).Run();
|
||||||
|
}
|
||||||
|
|
||||||
private void MakePasswordMaskedOrVisible()
|
private void MakePasswordMaskedOrVisible()
|
||||||
{
|
{
|
||||||
TextView password = (TextView) FindViewById(Resource.Id.password);
|
TextView password = (TextView) FindViewById(Resource.Id.password);
|
||||||
@ -470,7 +484,7 @@ namespace keepass2android
|
|||||||
//check if FileStorage setup is all done. Usually this should not occur here because the setup is
|
//check if FileStorage setup is all done. Usually this should not occur here because the setup is
|
||||||
//performed in FileSelectActivity, but e.g. if the user unlinks from Dropbox saving might fail and
|
//performed in FileSelectActivity, but e.g. if the user unlinks from Dropbox saving might fail and
|
||||||
//the user is returned here.
|
//the user is returned here.
|
||||||
if (App.Kp2a.GetFileStorage(_ioConnection).RequiredSetup != null)
|
if (App.Kp2a.GetFileStorage(_ioConnection).RequiresSetup(_ioConnection))
|
||||||
{
|
{
|
||||||
GoToFileSelectActivity();
|
GoToFileSelectActivity();
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="23" android:versionName="0.8.6" package="keepass2android.keepass2android" android:installLocation="auto">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="24" android:versionName="0.9 preview" package="keepass2android.keepass2android" android:installLocation="auto">
|
||||||
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="14" />
|
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="14" />
|
||||||
|
|
||||||
|
<permission android:description="@string/permission_desc"
|
||||||
|
android:icon="@drawable/ic_launcher"
|
||||||
|
android:label="KP2A internal file browsing"
|
||||||
|
android:name="keepass2android.keepass2android.permission.KP2aInternalFileBrowsing"
|
||||||
|
android:protectionLevel="signature" />
|
||||||
|
|
||||||
<application android:label="keepass2android" android:icon="@drawable/ic_launcher">
|
<application android:label="keepass2android" android:icon="@drawable/ic_launcher">
|
||||||
<activity android:name="com.dropbox.client2.android.AuthActivity" android:launchMode="singleTask" android:configChanges="orientation|keyboard">
|
<activity android:name="com.dropbox.client2.android.AuthActivity" android:launchMode="singleTask" android:configChanges="orientation|keyboard">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
@ -13,7 +20,20 @@
|
|||||||
</activity>
|
</activity>
|
||||||
<provider android:name="group.pals.android.lib.ui.filechooser.providers.localfile.LocalFileProvider" android:authorities="keepass2android.keepass2android.android-filechooser.localfile" android:exported="false" />
|
<provider android:name="group.pals.android.lib.ui.filechooser.providers.localfile.LocalFileProvider" android:authorities="keepass2android.keepass2android.android-filechooser.localfile" android:exported="false" />
|
||||||
<provider android:name="group.pals.android.lib.ui.filechooser.providers.history.HistoryProvider" android:authorities="keepass2android.keepass2android.android-filechooser.history" android:exported="false" />
|
<provider android:name="group.pals.android.lib.ui.filechooser.providers.history.HistoryProvider" android:authorities="keepass2android.keepass2android.android-filechooser.history" android:exported="false" />
|
||||||
<activity android:name="group.pals.android.lib.ui.filechooser.FileChooserActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:screenOrientation="user" android:theme="@style/Afc.Theme.Light" />
|
|
||||||
|
<activity android:name="group.pals.android.lib.ui.filechooser.FileChooserActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:screenOrientation="user" android:theme="@style/Afc.Theme.Light"
|
||||||
|
android:permission="keepass2android.keepass2android.permission.KP2aInternalFileBrowsing">
|
||||||
|
<intent-filter>
|
||||||
|
|
||||||
|
<action android:name="android.intent.action.GET_CONTENT" />
|
||||||
|
|
||||||
|
<data android:mimeType="*/*" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.OPENABLE" />
|
||||||
|
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<activity android:configChanges="keyboardHidden|orientation" android:label="@string/app_name" android:theme="@style/Base" android:name="keepass2android.PasswordActivity">
|
<activity android:configChanges="keyboardHidden|orientation" android:label="@string/app_name" android:theme="@style/Base" android:name="keepass2android.PasswordActivity">
|
||||||
<intent-filter android:label="@string/app_name">
|
<intent-filter android:label="@string/app_name">
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
@ -54,4 +74,5 @@
|
|||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="keepass2android.keepass2android.permission.KP2aInternalFileBrowsing" />
|
||||||
</manifest>
|
</manifest>
|
4412
src/keepass2android/Resources/Resource.designer.cs
generated
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
BIN
src/keepass2android/Resources/drawable-hdpi/ic_storage_file.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
src/keepass2android/Resources/drawable/ic_keepass2android.png
Normal file
After Width: | Height: | Size: 7.3 KiB |
After Width: | Height: | Size: 7.2 KiB |
BIN
src/keepass2android/Resources/drawable/ic_storage_androidget.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |
BIN
src/keepass2android/Resources/drawable/ic_storage_file.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
@ -8,13 +8,16 @@
|
|||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal">
|
android:layout_gravity="center_horizontal">
|
||||||
<ScrollView
|
|
||||||
|
<ScrollView
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="fill_parent">
|
android:layout_height="fill_parent">
|
||||||
<keepass2android.view.FileSelectButtons
|
|
||||||
android:id="@+id/file_select"
|
<keepass2android.view.FileSelectButtons
|
||||||
android:layout_width="fill_parent"
|
android:id="@+id/file_select"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<!-- Small hack because I need to include a list since this is a list activity -->
|
<!-- Small hack because I need to include a list since this is a list activity -->
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
android:text="Please select the cloud storage type you want to use:"
|
android:text="@string/select_storage_type"
|
||||||
style="@style/PaddedElement"
|
style="@style/PaddedElement"
|
||||||
android:id="@+id/textView"
|
android:id="@+id/textView"
|
||||||
android:layout_gravity="left|center_vertical"/>
|
android:layout_gravity="left|center_vertical"/>
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
<string name="issues">http://keepass2android.codeplex.com</string>
|
<string name="issues">http://keepass2android.codeplex.com</string>
|
||||||
<string name="oi_filemanager_market">market://details?id=org.openintents.filemanager</string>
|
<string name="oi_filemanager_market">market://details?id=org.openintents.filemanager</string>
|
||||||
<string name="oi_filemanager_web">https://openintents.googlecode.com/files/FileManager-2.0.2.apk</string>
|
<string name="oi_filemanager_web">https://openintents.googlecode.com/files/FileManager-2.0.2.apk</string>
|
||||||
|
<string name="permission_desc">KP2A Internal File Browsing Permission</string>
|
||||||
|
|
||||||
<!-- Preference settings -->
|
<!-- Preference settings -->
|
||||||
<string name="algorithm_key">algorithm</string>
|
<string name="algorithm_key">algorithm</string>
|
||||||
|
@ -320,16 +320,29 @@
|
|||||||
<string name="ok_donate">Tell me more!</string>
|
<string name="ok_donate">Tell me more!</string>
|
||||||
<string name="no_thanks">No, I don\'t like it that much</string>
|
<string name="no_thanks">No, I don\'t like it that much</string>
|
||||||
|
|
||||||
|
<string name="select_storage_type">Select the storage type:</string>
|
||||||
|
|
||||||
<string name="filestoragename_file">Local file</string>
|
<string name="filestoragename_file">Local file</string>
|
||||||
|
<string name="filestoragename_androidget">Get from third-party app</string>
|
||||||
|
<string name="filestoragename_androidsend">Send to third-party app</string>
|
||||||
<string name="filestoragename_ftp">FTP</string>
|
<string name="filestoragename_ftp">FTP</string>
|
||||||
<string name="filestoragename_http">HTTP (WebDav)</string>
|
<string name="filestoragename_http">HTTP (WebDav)</string>
|
||||||
<string name="filestoragename_https">HTTPS (WebDav)</string>
|
<string name="filestoragename_https">HTTPS (WebDav)</string>
|
||||||
<string name="filestoragename_dropbox">Dropbox</string>
|
<string name="filestoragename_dropbox">Dropbox</string>
|
||||||
<string name="filestoragename_gdrive">Google Drive</string>
|
<string name="filestoragename_gdrive">Google Drive</string>
|
||||||
|
|
||||||
|
<string name="filestorage_setup_title">File access initialization</string>
|
||||||
|
|
||||||
|
|
||||||
|
<string name="ChangeLog_title">Change log</string>
|
||||||
|
|
||||||
|
<string name="ChangeLog_0_9">
|
||||||
|
<b>Version 0.9</b>\n
|
||||||
|
* Support for Dropbox (Keepass2Android regular edition only)\n
|
||||||
|
* Integrated custom filechooser (based on android-filechooser by HBA)
|
||||||
|
</string>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<string name="ChangeLog_title">Change log</string>
|
|
||||||
|
|
||||||
<string name="ChangeLog_0_8_6">
|
<string name="ChangeLog_0_8_6">
|
||||||
<b>Version 0.8.6</b>\n
|
<b>Version 0.8.6</b>\n
|
||||||
* Support for Twofish cipher\n
|
* Support for Twofish cipher\n
|
||||||
|
@ -20,6 +20,8 @@ using System.Collections;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Android.App;
|
using Android.App;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
|
using Android.Database;
|
||||||
|
using Android.Provider;
|
||||||
using Android.Widget;
|
using Android.Widget;
|
||||||
using Android.Content.PM;
|
using Android.Content.PM;
|
||||||
using Uri = Android.Net.Uri;
|
using Uri = Android.Net.Uri;
|
||||||
@ -126,35 +128,36 @@ namespace keepass2android
|
|||||||
|
|
||||||
public static void ShowBrowseDialog(string filename, Activity act, int requestCodeBrowse, bool forSaving)
|
public static void ShowBrowseDialog(string filename, Activity act, int requestCodeBrowse, bool forSaving)
|
||||||
{
|
{
|
||||||
if ((!forSaving) && (IsIntentAvailable(act, Intent.ActionGetContent, "file/*"))) {
|
if ((!forSaving) && (IsIntentAvailable(act, Intent.ActionGetContent, "file/*")))
|
||||||
|
{
|
||||||
Intent i = new Intent(Intent.ActionGetContent);
|
Intent i = new Intent(Intent.ActionGetContent);
|
||||||
i.SetType("file/*");
|
i.SetType("file/*");
|
||||||
|
|
||||||
act.StartActivityForResult(i, requestCodeBrowse);
|
act.StartActivityForResult(i, requestCodeBrowse);
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (IsIntentAvailable(act, Intents.FileBrowse, null))
|
|
||||||
{
|
|
||||||
Intent i = new Intent(Intents.FileBrowse);
|
|
||||||
if (filename != null)
|
|
||||||
i.SetData(Uri.Parse("file://" + filename));
|
|
||||||
try
|
|
||||||
{
|
|
||||||
act.StartActivityForResult(i, requestCodeBrowse);
|
|
||||||
}
|
|
||||||
catch (ActivityNotFoundException)
|
|
||||||
{
|
|
||||||
BrowserDialog diag = new BrowserDialog(act);
|
|
||||||
diag.Show();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BrowserDialog diag = new BrowserDialog(act);
|
string defaultPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
|
||||||
diag.Show();
|
|
||||||
|
|
||||||
|
ShowInternalLocalFileChooser(act, requestCodeBrowse, forSaving, defaultPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ShowInternalLocalFileChooser(Activity act, int requestCodeBrowse, bool forSaving, string defaultPath)
|
||||||
|
{
|
||||||
|
const string fileProviderAuthority = "keepass2android.keepass2android.android-filechooser.localfile";
|
||||||
|
|
||||||
|
|
||||||
|
Intent i = Keepass2android.Kp2afilechooser.Kp2aFileChooserBridge.GetLaunchFileChooserIntent(act,
|
||||||
|
fileProviderAuthority,
|
||||||
|
defaultPath);
|
||||||
|
if (forSaving)
|
||||||
|
i.PutExtra("group.pals.android.lib.ui.filechooser.FileChooserActivity.save_dialog", true);
|
||||||
|
|
||||||
|
act.StartActivityForResult(i, requestCodeBrowse);
|
||||||
|
}
|
||||||
|
|
||||||
public static string IntentToFilename(Intent data, Context ctx)
|
public static string IntentToFilename(Intent data, Context ctx)
|
||||||
{
|
{
|
||||||
#if !EXCLUDE_FILECHOOSER
|
#if !EXCLUDE_FILECHOOSER
|
||||||
@ -165,7 +168,25 @@ namespace keepass2android
|
|||||||
Uri uri = (Uri) uris[0];
|
Uri uri = (Uri) uris[0];
|
||||||
return Group.Pals.Android.Lib.UI.Filechooser.Providers.BaseFileProviderUtils.GetRealUri(ctx, uri).ToString();
|
return Group.Pals.Android.Lib.UI.Filechooser.Providers.BaseFileProviderUtils.GetRealUri(ctx, uri).ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Uri uri = data.Data;
|
||||||
|
if ((uri != null) && (uri.Scheme == "content"))
|
||||||
|
{
|
||||||
|
String[] col = new String[] {MediaStore.MediaColumns.Data};
|
||||||
|
|
||||||
|
ICursor c1 = ctx.ContentResolver.Query(uri, col, null, null, null);
|
||||||
|
c1.MoveToFirst();
|
||||||
|
|
||||||
|
return c1.GetString(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Kp2aLog.Log(e.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
String filename = data.Data.Path;
|
String filename = data.Data.Path;
|
||||||
if (String.IsNullOrEmpty(filename))
|
if (String.IsNullOrEmpty(filename))
|
||||||
|
@ -377,7 +377,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
}
|
}
|
||||||
//TODO: catch!
|
//TODO: catch!
|
||||||
throw new Exception("Unknown protocol " + iocInfo);
|
throw new Exception("Unknown protocol " + iocInfo.Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<IFileStorage> FileStorages
|
public IEnumerable<IFileStorage> FileStorages
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
|
|
||||||
|
|
||||||
Keepass2Android is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Keepass2Android is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using Android.App;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.OS;
|
|
||||||
using Android.Views;
|
|
||||||
using Android.Widget;
|
|
||||||
using Android.Content.PM;
|
|
||||||
|
|
||||||
namespace keepass2android
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Dialog to offer to install OpenIntent file manager if there's no other browser installed
|
|
||||||
/// </summary>
|
|
||||||
public class BrowserDialog : Dialog {
|
|
||||||
|
|
||||||
public BrowserDialog(Context context) : base(context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnCreate(Bundle savedInstanceState) {
|
|
||||||
base.OnCreate(savedInstanceState);
|
|
||||||
SetContentView(Resource.Layout.browser_install);
|
|
||||||
SetTitle(Resource.String.file_browser);
|
|
||||||
|
|
||||||
Button cancel = (Button) FindViewById(Resource.Id.cancel);
|
|
||||||
cancel.Click += (sender, e) => Cancel();
|
|
||||||
|
|
||||||
Button market = (Button) FindViewById(Resource.Id.install_market);
|
|
||||||
market.Click += (sender, e) => {
|
|
||||||
Util.GotoUrl(Context, Resource.String.oi_filemanager_market);
|
|
||||||
Cancel();
|
|
||||||
}
|
|
||||||
;
|
|
||||||
if (!IsMarketInstalled()) {
|
|
||||||
market.Visibility = ViewStates.Gone;
|
|
||||||
}
|
|
||||||
|
|
||||||
Button web = (Button) FindViewById(Resource.Id.install_web);
|
|
||||||
web.Click += (sender, e) => {
|
|
||||||
Util.GotoUrl(Context, Resource.String.oi_filemanager_web);
|
|
||||||
Cancel();
|
|
||||||
}
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsMarketInstalled() {
|
|
||||||
PackageManager pm = Context.PackageManager;
|
|
||||||
|
|
||||||
try {
|
|
||||||
pm.GetPackageInfo("com.android.vending", 0);
|
|
||||||
} catch (PackageManager.NameNotFoundException) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -67,6 +67,7 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
Kp2aLog.Log("Provider.GetFileEntry " + filename);
|
||||||
return ConvertFileDescription(App.Kp2a.GetFileStorage(filename).GetFileDescription(ConvertPathToIoc(filename)));
|
return ConvertFileDescription(App.Kp2a.GetFileStorage(filename).GetFileDescription(ConvertPathToIoc(filename)));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -80,6 +81,7 @@ namespace keepass2android
|
|||||||
protected override void ListFiles(int taskId, string dirName, bool showHiddenFiles, int filterMode, int limit, string positiveRegex,
|
protected override void ListFiles(int taskId, string dirName, bool showHiddenFiles, int filterMode, int limit, string positiveRegex,
|
||||||
string negativeRegex, IList<FileEntry> fileList, bool[] hasMoreFiles)
|
string negativeRegex, IList<FileEntry> fileList, bool[] hasMoreFiles)
|
||||||
{
|
{
|
||||||
|
Kp2aLog.Log("Provider.ListFiles " + dirName);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var dirContents = App.Kp2a.GetFileStorage(dirName).ListContents(ConvertPathToIoc(dirName));
|
var dirContents = App.Kp2a.GetFileStorage(dirName).ListContents(ConvertPathToIoc(dirName));
|
||||||
|
@ -63,7 +63,6 @@ namespace keepass2android
|
|||||||
view.FileSelectButtons _fileSelectButtons;
|
view.FileSelectButtons _fileSelectButtons;
|
||||||
|
|
||||||
internal AppTask AppTask;
|
internal AppTask AppTask;
|
||||||
private IOConnectionInfo _iocToLaunch;
|
|
||||||
|
|
||||||
public const string NoForwardToPasswordActivity = "NoForwardToPasswordActivity";
|
public const string NoForwardToPasswordActivity = "NoForwardToPasswordActivity";
|
||||||
|
|
||||||
@ -234,26 +233,18 @@ namespace keepass2android
|
|||||||
|
|
||||||
EventHandler openFileButtonClick = (sender, e) =>
|
EventHandler openFileButtonClick = (sender, e) =>
|
||||||
{
|
{
|
||||||
string defaultFilename = Android.OS.Environment.ExternalStorageDirectory + GetString(Resource.String.default_file_path);
|
Intent intent = new Intent(this, typeof(FileStorageSelectionActivity));
|
||||||
const string detailsText = "";
|
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, true);
|
||||||
ShowFilenameDialog(true, false, true, defaultFilename, detailsText, Intents.RequestCodeFileBrowseForOpen);
|
StartActivityForResult(intent, 0);
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
openFileButton.Click += openFileButtonClick;
|
openFileButton.Click += openFileButtonClick;
|
||||||
//OPEN URL
|
//OPEN URL
|
||||||
Button openUrlButton = (Button)FindViewById(Resource.Id.start_open_url);
|
Button openUrlButton = (Button)FindViewById(Resource.Id.start_open_url);
|
||||||
|
|
||||||
#if NoNet
|
|
||||||
openUrlButton.Visibility = ViewStates.Gone;
|
openUrlButton.Visibility = ViewStates.Gone;
|
||||||
#endif
|
|
||||||
|
|
||||||
//EventHandler openUrlButtonClick = (sender, e) => ShowFilenameDialog(true, false, false, "", GetString(Resource.String.enter_filename_details_url), Intents.RequestCodeFileBrowseForOpen);
|
//EventHandler openUrlButtonClick = (sender, e) => ShowFilenameDialog(true, false, false, "", GetString(Resource.String.enter_filename_details_url), Intents.RequestCodeFileBrowseForOpen);
|
||||||
openUrlButton.Click += (sender, args) =>
|
|
||||||
{
|
|
||||||
Intent intent = new Intent(this, typeof(FileStorageSelectionActivity));
|
|
||||||
StartActivityForResult(intent, 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
//CREATE NEW
|
//CREATE NEW
|
||||||
Button createNewButton = (Button)FindViewById(Resource.Id.start_create);
|
Button createNewButton = (Button)FindViewById(Resource.Id.start_create);
|
||||||
@ -282,20 +273,6 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
AppTask = AppTask.CreateFromBundle(savedInstanceState);
|
AppTask = AppTask.CreateFromBundle(savedInstanceState);
|
||||||
_recentMode = savedInstanceState.GetBoolean(BundleKeyRecentMode, _recentMode);
|
_recentMode = savedInstanceState.GetBoolean(BundleKeyRecentMode, _recentMode);
|
||||||
|
|
||||||
string filenameToLaunch = savedInstanceState.GetString(PasswordActivity.KeyFilename);
|
|
||||||
if (filenameToLaunch != null)
|
|
||||||
{
|
|
||||||
_iocToLaunch = new IOConnectionInfo()
|
|
||||||
{
|
|
||||||
Path = filenameToLaunch,
|
|
||||||
UserName = savedInstanceState.GetString(PasswordActivity.KeyServerusername),
|
|
||||||
Password = savedInstanceState.GetString(PasswordActivity.KeyServerpassword),
|
|
||||||
CredSaveMode = (IOCredSaveMode) savedInstanceState.GetInt(PasswordActivity.KeyServercredmode)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -322,13 +299,6 @@ namespace keepass2android
|
|||||||
AppTask.ToBundle(outState);
|
AppTask.ToBundle(outState);
|
||||||
outState.PutBoolean(BundleKeyRecentMode, _recentMode);
|
outState.PutBoolean(BundleKeyRecentMode, _recentMode);
|
||||||
|
|
||||||
if (_iocToLaunch != null)
|
|
||||||
{
|
|
||||||
outState.PutString(PasswordActivity.KeyFilename, _iocToLaunch.Path);
|
|
||||||
outState.PutString(PasswordActivity.KeyServerusername, _iocToLaunch.UserName);
|
|
||||||
outState.PutString(PasswordActivity.KeyServerpassword, _iocToLaunch.Password);
|
|
||||||
outState.PutInt(PasswordActivity.KeyServercredmode, (int)_iocToLaunch.CredSaveMode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class LaunchGroupActivity : FileOnFinish {
|
private class LaunchGroupActivity : FileOnFinish {
|
||||||
@ -407,15 +377,6 @@ namespace keepass2android
|
|||||||
void LaunchPasswordActivityForIoc(IOConnectionInfo ioc)
|
void LaunchPasswordActivityForIoc(IOConnectionInfo ioc)
|
||||||
{
|
{
|
||||||
IFileStorage fileStorage = App.Kp2a.GetFileStorage(ioc);
|
IFileStorage fileStorage = App.Kp2a.GetFileStorage(ioc);
|
||||||
if (fileStorage.RequiredSetup != null)
|
|
||||||
{
|
|
||||||
if (!fileStorage.RequiredSetup.TrySetup(this))
|
|
||||||
{
|
|
||||||
//store ioc to launch. TrySetup hopefully launched another activity so we can check again in OnResume
|
|
||||||
_iocToLaunch = ioc;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileStorage.RequiresCredentials(ioc))
|
if (fileStorage.RequiresCredentials(ioc))
|
||||||
{
|
{
|
||||||
@ -485,9 +446,19 @@ namespace keepass2android
|
|||||||
if (resultCode == KeePass.ExitFileStorageSelectionOk)
|
if (resultCode == KeePass.ExitFileStorageSelectionOk)
|
||||||
{
|
{
|
||||||
#if !EXCLUDE_FILECHOOSER
|
#if !EXCLUDE_FILECHOOSER
|
||||||
Intent i = Keepass2android.Kp2afilechooser.Kp2aFileChooserBridge.GetLaunchFileChooserIntent(this, FileChooserFileProvider.TheAuthority, data.GetStringExtra("protocolId")+":///");
|
string protocolId = data.GetStringExtra("protocolId");
|
||||||
|
|
||||||
|
if (protocolId == "androidget")
|
||||||
|
{
|
||||||
|
string defaultFilename = Environment.ExternalStorageDirectory +
|
||||||
|
GetString(Resource.String.default_file_path);
|
||||||
|
Util.ShowBrowseDialog(defaultFilename, this, Intents.RequestCodeFileBrowseForOpen, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
App.Kp2a.GetFileStorage(protocolId).StartSelectFile(new FileStorageSetupInitiatorActivity(this, OnActivityResult), false, 0, protocolId);
|
||||||
|
}
|
||||||
|
|
||||||
StartActivityForResult(i, Intents.RequestCodeFileBrowseForOpen);
|
|
||||||
#else
|
#else
|
||||||
Toast.MakeText(this, "TODO: make this more flexible.", ToastLength.Long).Show();
|
Toast.MakeText(this, "TODO: make this more flexible.", ToastLength.Long).Show();
|
||||||
IOConnectionInfo ioc = new IOConnectionInfo
|
IOConnectionInfo ioc = new IOConnectionInfo
|
||||||
@ -528,6 +499,36 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resultCode == (Result) FileStorageResults.FileUsagePrepared)
|
||||||
|
{
|
||||||
|
IOConnectionInfo ioc = new IOConnectionInfo();
|
||||||
|
PasswordActivity.SetIoConnectionFromIntent(ioc, data);
|
||||||
|
LaunchPasswordActivityForIoc(ioc);
|
||||||
|
}
|
||||||
|
if (resultCode == (Result)FileStorageResults.FileChooserPrepared)
|
||||||
|
{
|
||||||
|
IOConnectionInfo ioc = new IOConnectionInfo();
|
||||||
|
PasswordActivity.SetIoConnectionFromIntent(ioc, data);
|
||||||
|
#if !EXCLUDE_FILECHOOSER
|
||||||
|
StartFileChooser(ioc.Path);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartFileChooser(string defaultPath)
|
||||||
|
{
|
||||||
|
Kp2aLog.Log("FSA: defaultPath="+defaultPath);
|
||||||
|
string fileProviderAuthority = FileChooserFileProvider.TheAuthority;
|
||||||
|
if (defaultPath.StartsWith("file://"))
|
||||||
|
{
|
||||||
|
fileProviderAuthority = "keepass2android.keepass2android.android-filechooser.localfile";
|
||||||
|
defaultPath = Environment.ExternalStorageDirectory + GetString(Resource.String.default_file_path);
|
||||||
|
}
|
||||||
|
Intent i = Keepass2android.Kp2afilechooser.Kp2aFileChooserBridge.GetLaunchFileChooserIntent(this, fileProviderAuthority,
|
||||||
|
defaultPath);
|
||||||
|
|
||||||
|
StartActivityForResult(i, Intents.RequestCodeFileBrowseForOpen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -546,26 +547,7 @@ namespace keepass2android
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if we are resuming after setting up the file storage:
|
|
||||||
if (_iocToLaunch != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
IOConnectionInfo iocToLaunch = _iocToLaunch;
|
|
||||||
_iocToLaunch = null;
|
|
||||||
|
|
||||||
IFileStorageSetupOnResume fsSetup = App.Kp2a.GetFileStorage(iocToLaunch).RequiredSetup as IFileStorageSetupOnResume;
|
|
||||||
if ((fsSetup == null) || (fsSetup.TrySetupOnResume(this)))
|
|
||||||
{
|
|
||||||
LaunchPasswordActivityForIoc(iocToLaunch);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Toast.MakeText(this, e.Message, ToastLength.Long).Show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_fileSelectButtons.UpdateExternalStorageWarning();
|
_fileSelectButtons.UpdateExternalStorageWarning();
|
||||||
|
|
||||||
@ -591,7 +573,7 @@ namespace keepass2android
|
|||||||
StartManagingCursor(filesCursor);
|
StartManagingCursor(filesCursor);
|
||||||
filesCursor.MoveToFirst();
|
filesCursor.MoveToFirst();
|
||||||
IOConnectionInfo ioc = _DbHelper.CursorToIoc(filesCursor);
|
IOConnectionInfo ioc = _DbHelper.CursorToIoc(filesCursor);
|
||||||
if (App.Kp2a.GetFileStorage(ioc).RequiredSetup == null)
|
if (App.Kp2a.GetFileStorage(ioc).RequiresSetup(ioc) == false)
|
||||||
{
|
{
|
||||||
LaunchPasswordActivityForIoc(ioc);
|
LaunchPasswordActivityForIoc(ioc);
|
||||||
}
|
}
|
||||||
@ -684,6 +666,10 @@ namespace keepass2android
|
|||||||
Android.Database.ICursor cursor = ca.Cursor;
|
Android.Database.ICursor cursor = ca.Cursor;
|
||||||
cursor.Requery();
|
cursor.Requery();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
82
src/keepass2android/fileselect/FileStorageSetupActivity.cs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
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;
|
||||||
|
using Keepass2android.Javafilestorage;
|
||||||
|
using keepass2android.Io;
|
||||||
|
using JavaFileStorage = Keepass2android.Javafilestorage.JavaFileStorage;
|
||||||
|
|
||||||
|
namespace keepass2android.fileselect
|
||||||
|
{
|
||||||
|
[Activity(Label = "@string/filestorage_setup_title",Theme="@style/Base")]
|
||||||
|
public class FileStorageSetupActivity : Activity, IFileStorageSetupActivity
|
||||||
|
#if !EXCLUDE_JAVAFILESTORAGE
|
||||||
|
,IJavaFileStorageFileStorageSetupActivity
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
protected override void OnCreate(Bundle bundle)
|
||||||
|
{
|
||||||
|
base.OnCreate(bundle);
|
||||||
|
|
||||||
|
Ioc = new IOConnectionInfo();
|
||||||
|
PasswordActivity.SetIoConnectionFromIntent(Ioc, Intent);
|
||||||
|
|
||||||
|
Kp2aLog.Log("FSSA.OnCreate with " + Ioc.Path);
|
||||||
|
|
||||||
|
ProcessName = Intent.GetStringExtra(FileStorageSetupDefs.ExtraProcessName);
|
||||||
|
IsForSave = Intent.GetBooleanExtra(FileStorageSetupDefs.ExtraIsForSave, false);
|
||||||
|
if (bundle == null)
|
||||||
|
State = new Bundle();
|
||||||
|
else
|
||||||
|
State = (Bundle) bundle.Clone();
|
||||||
|
|
||||||
|
App.Kp2a.GetFileStorage(Ioc).OnCreate(this, bundle);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnStart()
|
||||||
|
{
|
||||||
|
base.OnStart();
|
||||||
|
App.Kp2a.GetFileStorage(Ioc).OnStart(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnResume()
|
||||||
|
{
|
||||||
|
base.OnResume();
|
||||||
|
App.Kp2a.GetFileStorage(Ioc).OnResume(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
|
||||||
|
{
|
||||||
|
base.OnActivityResult(requestCode, resultCode, data);
|
||||||
|
App.Kp2a.GetFileStorage(Ioc).OnActivityResult(this, requestCode, (int) resultCode, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnSaveInstanceState(Bundle outState)
|
||||||
|
{
|
||||||
|
base.OnSaveInstanceState(outState);
|
||||||
|
|
||||||
|
outState.PutAll(State);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IOConnectionInfo Ioc { get; private set; }
|
||||||
|
public string Path
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return App.Kp2a.GetFileStorage(Ioc).IocToPath(Ioc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string ProcessName { get; private set; }
|
||||||
|
public bool IsForSave { get; private set; }
|
||||||
|
public Bundle State { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using Android.App;
|
||||||
|
using Android.Content;
|
||||||
|
using KeePassLib.Serialization;
|
||||||
|
using Keepass2android.Javafilestorage;
|
||||||
|
using keepass2android.Io;
|
||||||
|
using keepass2android.fileselect;
|
||||||
|
|
||||||
|
namespace keepass2android
|
||||||
|
{
|
||||||
|
public class FileStorageSetupInitiatorActivity:
|
||||||
|
#if !EXCLUDE_JAVAFILESTORAGE
|
||||||
|
Java.Lang.Object
|
||||||
|
,IJavaFileStorageFileStorageSetupInitiatorActivity
|
||||||
|
#endif
|
||||||
|
, IFileStorageSetupInitiatorActivity
|
||||||
|
{
|
||||||
|
private readonly Activity _activity;
|
||||||
|
private readonly Action<int, Result, Intent> _onActivityResult;
|
||||||
|
|
||||||
|
public FileStorageSetupInitiatorActivity(Activity activity, Action<int,Result,Intent> onActivityResult)
|
||||||
|
{
|
||||||
|
_activity = activity;
|
||||||
|
_onActivityResult = onActivityResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartSelectFileProcess(IOConnectionInfo ioc, bool isForSave, int requestCode)
|
||||||
|
{
|
||||||
|
Kp2aLog.Log("FSSIA: StartSelectFileProcess "+ioc.Path);
|
||||||
|
Intent fileStorageSetupIntent = new Intent(_activity, typeof(FileStorageSetupActivity));
|
||||||
|
fileStorageSetupIntent.PutExtra(FileStorageSetupDefs.ExtraProcessName, FileStorageSetupDefs.ProcessNameSelectfile);
|
||||||
|
fileStorageSetupIntent.PutExtra(FileStorageSetupDefs.ExtraIsForSave, isForSave);
|
||||||
|
PasswordActivity.PutIoConnectionToIntent(ioc, fileStorageSetupIntent);
|
||||||
|
|
||||||
|
_activity.StartActivityForResult(fileStorageSetupIntent, requestCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartFileUsageProcess(IOConnectionInfo ioc, int requestCode)
|
||||||
|
{
|
||||||
|
Intent fileStorageSetupIntent = new Intent(_activity, typeof(FileStorageSetupActivity));
|
||||||
|
fileStorageSetupIntent.PutExtra(FileStorageSetupDefs.ExtraProcessName, FileStorageSetupDefs.ProcessNameFileUsageSetup);
|
||||||
|
PasswordActivity.PutIoConnectionToIntent(ioc, fileStorageSetupIntent);
|
||||||
|
|
||||||
|
_activity.StartActivityForResult(fileStorageSetupIntent, requestCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnImmediateResult(int requestCode, int result, Intent intent)
|
||||||
|
{
|
||||||
|
_onActivityResult(requestCode, (Result)result, intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Activity Activity {
|
||||||
|
get { return _activity; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void IocToIntent(Intent intent, IOConnectionInfo ioc)
|
||||||
|
{
|
||||||
|
PasswordActivity.PutIoConnectionToIntent(ioc, intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PerformManualFileSelect(bool isForSave, int requestCode, string protocolId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartFileUsageProcess(string p0, int p1)
|
||||||
|
{
|
||||||
|
StartFileUsageProcess(new IOConnectionInfo() { Path = p0 }, p1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartSelectFileProcess(string p0, bool p1, int p2)
|
||||||
|
{
|
||||||
|
StartSelectFileProcess(new IOConnectionInfo() { Path = p0 }, p1, p2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,7 +24,7 @@
|
|||||||
<DebugType>full</DebugType>
|
<DebugType>full</DebugType>
|
||||||
<Optimize>False</Optimize>
|
<Optimize>False</Optimize>
|
||||||
<OutputPath>bin\Debug</OutputPath>
|
<OutputPath>bin\Debug</OutputPath>
|
||||||
<DefineConstants>DEBUG;EXCLUDE_TWOFISH;EXCLUDE_KEYBOARD;EXCLUDE_KEYTRANSFORM;EXCLUDE_FILECHOOSER;EXCLUDE_JAVAFILESTORAGE</DefineConstants>
|
<DefineConstants>DEBUG;INCLUDE_TWOFISH;INCLUDE_KEYBOARD;INCLUDE_KEYTRANSFORM;INCLUDE_FILECHOOSER;INCLUDE_JAVAFILESTORAGE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<ConsolePause>False</ConsolePause>
|
<ConsolePause>False</ConsolePause>
|
||||||
@ -79,6 +79,8 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="fileselect\FileChooserFileProvider.cs" />
|
<Compile Include="fileselect\FileChooserFileProvider.cs" />
|
||||||
|
<Compile Include="fileselect\FileStorageSetupActivity.cs" />
|
||||||
|
<Compile Include="fileselect\FileStorageSetupInitiatorActivity.cs" />
|
||||||
<Compile Include="FileStorageSelectionActivity.cs" />
|
<Compile Include="FileStorageSelectionActivity.cs" />
|
||||||
<Compile Include="DonateReminder.cs" />
|
<Compile Include="DonateReminder.cs" />
|
||||||
<Compile Include="app\ApplicationBroadcastReceiver.cs" />
|
<Compile Include="app\ApplicationBroadcastReceiver.cs" />
|
||||||
@ -96,7 +98,6 @@
|
|||||||
<Compile Include="settings\DatabaseSettingsActivity.cs" />
|
<Compile Include="settings\DatabaseSettingsActivity.cs" />
|
||||||
<Compile Include="Utils\Util.cs" />
|
<Compile Include="Utils\Util.cs" />
|
||||||
<Compile Include="intents\Intents.cs" />
|
<Compile Include="intents\Intents.cs" />
|
||||||
<Compile Include="fileselect\BrowserDialog.cs" />
|
|
||||||
<Compile Include="timeout\TimeoutHelper.cs" />
|
<Compile Include="timeout\TimeoutHelper.cs" />
|
||||||
<Compile Include="GroupActivity.cs" />
|
<Compile Include="GroupActivity.cs" />
|
||||||
<Compile Include="GroupBaseActivity.cs" />
|
<Compile Include="GroupBaseActivity.cs" />
|
||||||
@ -253,7 +254,7 @@
|
|||||||
<None Include="Resources\values-vi\strings.xml">
|
<None Include="Resources\values-vi\strings.xml">
|
||||||
<Visible>False</Visible>
|
<Visible>False</Visible>
|
||||||
</None>
|
</None>
|
||||||
<None Include="..\java\kp2akeytransform\libs\mips\libfinal-key.so" Condition="!$(DefineConstants.Contains('EXCLUDE_KEYTRANSFORM'))">
|
<None Include="..\java\kp2akeytransform\libs\mips\libfinal-key.so" Condition="!$(DefineConstants.Contains('EXCLUDE_KEYTRANSFORM'))">
|
||||||
<Link>libs\mips\libfinal-key.so</Link>
|
<Link>libs\mips\libfinal-key.so</Link>
|
||||||
</None>
|
</None>
|
||||||
<None Include="Resources\drawable-hdpi\Thumbs.db">
|
<None Include="Resources\drawable-hdpi\Thumbs.db">
|
||||||
@ -700,11 +701,11 @@
|
|||||||
</MonoDevelop>
|
</MonoDevelop>
|
||||||
</ProjectExtensions>
|
</ProjectExtensions>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AndroidNativeLibrary Include="..\java\kp2akeytransform\libs\armeabi\libfinal-key.so" Condition="!$(DefineConstants.Contains('EXCLUDE_KEYTRANSFORM'))">
|
<AndroidNativeLibrary Include="..\java\kp2akeytransform\libs\armeabi\libfinal-key.so" Condition="!$(DefineConstants.Contains('EXCLUDE_KEYTRANSFORM'))">
|
||||||
<Link>libs\armeabi\libfinal-key.so</Link>
|
<Link>libs\armeabi\libfinal-key.so</Link>
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</AndroidNativeLibrary>
|
</AndroidNativeLibrary>
|
||||||
<AndroidNativeLibrary Include="..\java\kp2akeytransform\libs\armeabi-v7a\libfinal-key.so" Condition="!$(DefineConstants.Contains('EXCLUDE_KEYTRANSFORM'))">
|
<AndroidNativeLibrary Include="..\java\kp2akeytransform\libs\armeabi-v7a\libfinal-key.so" Condition="!$(DefineConstants.Contains('EXCLUDE_KEYTRANSFORM'))">
|
||||||
<Link>libs\armeabi-v7a\libfinal-key.so</Link>
|
<Link>libs\armeabi-v7a\libfinal-key.so</Link>
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</AndroidNativeLibrary>
|
</AndroidNativeLibrary>
|
||||||
@ -816,4 +817,28 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AndroidResource Include="Resources\drawable-hdpi\ic_storage_http.png" />
|
<AndroidResource Include="Resources\drawable-hdpi\ic_storage_http.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\drawable\ic_storage_androidget.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\drawable\ic_storage_androidsend.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\drawable-hdpi\ic_storage_androidget.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\drawable-hdpi\ic_storage_androidsend.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\drawable-hdpi\ic_storage_file.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\drawable\ic_storage_file.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\drawable\ic_keepass2android.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\drawable\ic_keepass2android_nonet.png" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|