* 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>
|
||||
<Optimize>False</Optimize>
|
||||
<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>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>False</ConsolePause>
|
||||
|
@ -2,16 +2,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using KeePassLib.Serialization;
|
||||
using KeePassLib.Utility;
|
||||
|
||||
@ -89,8 +82,6 @@ namespace keepass2android.Io
|
||||
return new BuiltInFileTransaction(ioc, useFileTransaction);
|
||||
}
|
||||
|
||||
public IFileStorageSetup RequiredSetup { get { return null; } }
|
||||
|
||||
public class BuiltInFileTransaction : IWriteTransaction
|
||||
{
|
||||
private readonly FileTransactionEx _transaction;
|
||||
@ -155,5 +146,54 @@ namespace keepass2android.Io
|
||||
//TODO
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool RequiresSetup(IOConnectionInfo ioConnection)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public string IocToPath(IOConnectionInfo ioc)
|
||||
{
|
||||
return ioc.Path;
|
||||
}
|
||||
|
||||
public void StartSelectFile(IFileStorageSetupInitiatorActivity activity, bool isForSave, int requestCode, string protocolId)
|
||||
{
|
||||
if (protocolId != "file")
|
||||
activity.PerformManualFileSelect(isForSave, requestCode, protocolId);
|
||||
else
|
||||
{
|
||||
Intent intent = new Intent();
|
||||
activity.IocToIntent(intent, new IOConnectionInfo() { Path = protocolId+"://"});
|
||||
activity.OnImmediateResult(requestCode, (int) FileStorageResults.FileChooserPrepared, intent);
|
||||
}
|
||||
}
|
||||
|
||||
public void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode)
|
||||
{
|
||||
Intent intent = new Intent();
|
||||
activity.IocToIntent(intent, ioc);
|
||||
activity.OnImmediateResult(requestCode, (int) FileStorageResults.FileUsagePrepared, intent);
|
||||
}
|
||||
|
||||
public void OnCreate(IFileStorageSetupActivity activity, Bundle savedInstanceState)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnResume(IFileStorageSetupActivity activity)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnStart(IFileStorageSetupActivity activity)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnActivityResult(IFileStorageSetupActivity activity, int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,8 @@ using System.IO;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using KeePassLib.Cryptography;
|
||||
using KeePassLib.Serialization;
|
||||
using KeePassLib.Utility;
|
||||
@ -19,7 +21,7 @@ namespace keepass2android.Io
|
||||
/// called when a save operation only updated the cache but not the remote file
|
||||
/// </summary>
|
||||
/// <param name="ioc">The file which we tried to write</param>
|
||||
/// <param name="e">The exception why the remote file couldn't be updated</param>
|
||||
/// <param name="ex">The exception why the remote file couldn't be updated</param>
|
||||
void CouldntSaveToRemote(IOConnectionInfo ioc, Exception ex);
|
||||
|
||||
/// <summary>
|
||||
@ -398,8 +400,6 @@ namespace keepass2android.Io
|
||||
return new CachedWriteTransaction(ioc, useFileTransaction, this);
|
||||
}
|
||||
|
||||
public IFileStorageSetup RequiredSetup { get { return _cachedStorage.RequiredSetup; } }
|
||||
|
||||
public bool CompleteIoId()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
@ -436,6 +436,46 @@ namespace keepass2android.Io
|
||||
return _cachedStorage.GetFileDescription(ioc);
|
||||
}
|
||||
|
||||
public bool RequiresSetup(IOConnectionInfo ioConnection)
|
||||
{
|
||||
return _cachedStorage.RequiresSetup(ioConnection);
|
||||
}
|
||||
|
||||
public string IocToPath(IOConnectionInfo ioc)
|
||||
{
|
||||
return _cachedStorage.IocToPath(ioc);
|
||||
}
|
||||
|
||||
public void StartSelectFile(IFileStorageSetupInitiatorActivity activity, bool isForSave, int requestCode, string protocolId)
|
||||
{
|
||||
_cachedStorage.StartSelectFile(activity, isForSave, requestCode, protocolId);
|
||||
}
|
||||
|
||||
public void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode)
|
||||
{
|
||||
_cachedStorage.PrepareFileUsage(activity, ioc, requestCode);
|
||||
}
|
||||
|
||||
public void OnCreate(IFileStorageSetupActivity activity, Bundle savedInstanceState)
|
||||
{
|
||||
_cachedStorage.OnCreate(activity, savedInstanceState);
|
||||
}
|
||||
|
||||
public void OnResume(IFileStorageSetupActivity activity)
|
||||
{
|
||||
_cachedStorage.OnResume(activity);
|
||||
}
|
||||
|
||||
public void OnStart(IFileStorageSetupActivity activity)
|
||||
{
|
||||
_cachedStorage.OnStart(activity);
|
||||
}
|
||||
|
||||
public void OnActivityResult(IFileStorageSetupActivity activity, int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
_cachedStorage.OnActivityResult(activity, requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
|
||||
public string GetBaseVersionHash(IOConnectionInfo ioc)
|
||||
{
|
||||
|
@ -16,17 +16,14 @@ using Keepass2android.Javafilestorage;
|
||||
|
||||
namespace keepass2android.Io
|
||||
{
|
||||
public class DropboxFileStorage: JavaFileStorage
|
||||
public partial class DropboxFileStorage: JavaFileStorage
|
||||
{
|
||||
public DropboxFileStorage(Context ctx, IKp2aApp app) :
|
||||
base(new Keepass2android.Javafilestorage.DropboxFileStorage(ctx), app)
|
||||
base(new Keepass2android.Javafilestorage.DropboxFileStorage(ctx, AppKey, AppSecret), app)
|
||||
{
|
||||
}
|
||||
|
||||
protected override string Protocol
|
||||
{
|
||||
get { return "dropbox"; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
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
|
||||
{
|
||||
public class GDriveFileStorage: IFileStorage
|
||||
/*public class GDriveFileStorage: IFileStorage
|
||||
{
|
||||
public IEnumerable<string> SupportedProtocols { get { yield return "gdrive"; } }
|
||||
public void Delete(IOConnectionInfo ioc)
|
||||
@ -42,7 +42,6 @@ namespace keepass2android.Io
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IFileStorageSetup RequiredSetup { get; private set; }
|
||||
|
||||
public bool CompleteIoId()
|
||||
{
|
||||
@ -78,5 +77,5 @@ namespace keepass2android.Io
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
@ -1,20 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using KeePassLib.Keys;
|
||||
using KeePassLib.Serialization;
|
||||
|
||||
namespace keepass2android.Io
|
||||
{
|
||||
|
||||
public enum FileStorageResults
|
||||
{
|
||||
FullFilenameSelected = 874345 + 1,
|
||||
FileChooserPrepared = FullFilenameSelected + 1,
|
||||
FileUsagePrepared = FileChooserPrepared + 1
|
||||
}
|
||||
|
||||
public static class FileStorageSetupDefs
|
||||
{
|
||||
public static String ProcessNameSelectfile = "SELECT_FILE";
|
||||
public static String ProcessNameFileUsageSetup = "FILE_USAGE_SETUP";
|
||||
|
||||
public static String ExtraProcessName = "EXTRA_PROCESS_NAME";
|
||||
public static String ExtraPath = "PATH";
|
||||
public static String ExtraIsForSave = "IS_FOR_SAVE";
|
||||
public static String ExtraErrorMessage = "EXTRA_ERROR_MESSAGE";
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called as a callback from CheckForFileChangeAsync.
|
||||
/// </summary>
|
||||
@ -69,14 +82,6 @@ namespace keepass2android.Io
|
||||
/// <param name="useFileTransaction">if true, force to use file system level transaction. This might be ignored if the file storage has built in transaction support</param>
|
||||
IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an instance of an implementation of IFileStorageSetup or one of the more complex interfaces.
|
||||
/// Depending on the type returned, the caller should try to follow the interface as close as possible.
|
||||
/// Returns null if the file storage is setup or doesn't require anything to work.
|
||||
/// </summary>
|
||||
/// This is due to different storage types requiring different workflows for authentication processes
|
||||
IFileStorageSetup RequiredSetup { get; }
|
||||
|
||||
/// <summary>
|
||||
/// brings up a dialog to query credentials or something like this.
|
||||
/// </summary>
|
||||
@ -111,32 +116,36 @@ namespace keepass2android.Io
|
||||
/// returns the description of the given file
|
||||
/// </summary>
|
||||
FileDescription GetFileDescription(IOConnectionInfo ioc);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base interface for required setup code
|
||||
/// returns true if everything is ok with connecting to the given file.
|
||||
/// Returns False if PrepareFileUsage must be called first.
|
||||
/// </summary>
|
||||
public interface IFileStorageSetup
|
||||
{
|
||||
/// <summary>
|
||||
/// call this when the user explicitly wants to use this file storage. Might require user interaction.
|
||||
/// May throw if the setup failed permanentaly.
|
||||
/// </summary>
|
||||
/// <returns>true if the setup was succesful immediately (without UI). Returns false if setup was not successful but no error occured or can be displayed.</returns>
|
||||
bool TrySetup(Activity activity);
|
||||
}
|
||||
bool RequiresSetup(IOConnectionInfo ioConnection);
|
||||
|
||||
/// <summary>
|
||||
/// Interface which can be used additionally for an IFileStorageSetup to indicate that setup must be completed in OnResume()
|
||||
/// converts the ioc to a path which may contain the credentials
|
||||
/// </summary>
|
||||
public interface IFileStorageSetupOnResume
|
||||
{
|
||||
string IocToPath(IOConnectionInfo ioc);
|
||||
|
||||
/// <summary>
|
||||
/// call this after TrySetup() returned false in the next OnResume()
|
||||
/// May throw if the setup failed permanentaly.
|
||||
/// Initiates the process for choosing a file in the given file storage.
|
||||
/// The file storage should either call OnImmediateResult or StartSelectFileProcess
|
||||
/// </summary>
|
||||
/// <returns>true if setup was succesful</returns>
|
||||
bool TrySetupOnResume(Activity activity);
|
||||
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
|
||||
|
@ -3,6 +3,8 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using KeePassLib.Serialization;
|
||||
using KeePassLib.Utility;
|
||||
#if !EXCLUDE_JAVAFILESTORAGE
|
||||
@ -16,6 +18,8 @@ namespace keepass2android.Io
|
||||
#if !EXCLUDE_JAVAFILESTORAGE
|
||||
public abstract class JavaFileStorage: IFileStorage
|
||||
{
|
||||
protected string Protocol { get { return _jfs.ProtocolId; } }
|
||||
|
||||
public IEnumerable<string> SupportedProtocols { get { yield return Protocol; } }
|
||||
|
||||
|
||||
@ -64,7 +68,7 @@ namespace keepass2android.Io
|
||||
{
|
||||
try
|
||||
{
|
||||
return Jfs.GetCurrentFileVersionFast(ioc.Path);
|
||||
return Jfs.GetCurrentFileVersionFast(IocToPath(ioc));
|
||||
}
|
||||
catch (Java.Lang.Exception e)
|
||||
{
|
||||
@ -103,55 +107,11 @@ namespace keepass2android.Io
|
||||
return new JavaFileStorageWriteTransaction(IocToPath(ioc), useFileTransaction, this);
|
||||
}
|
||||
|
||||
public IFileStorageSetup RequiredSetup
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Jfs.IsConnected)
|
||||
return null;
|
||||
return new JavaFileStorageSetup(this);
|
||||
}
|
||||
}
|
||||
|
||||
internal IJavaFileStorage Jfs
|
||||
{
|
||||
get { return _jfs; }
|
||||
}
|
||||
|
||||
public class JavaFileStorageSetup : IFileStorageSetup, IFileStorageSetupOnResume
|
||||
{
|
||||
private readonly JavaFileStorage _javaFileStorage;
|
||||
|
||||
public JavaFileStorageSetup(JavaFileStorage javaFileStorage)
|
||||
{
|
||||
_javaFileStorage = javaFileStorage;
|
||||
}
|
||||
|
||||
public bool TrySetup(Activity activity)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _javaFileStorage.Jfs.TryConnect(activity);
|
||||
}
|
||||
catch (Java.Lang.Exception e)
|
||||
{
|
||||
throw _javaFileStorage.LogAndConvertJavaException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TrySetupOnResume(Activity activity)
|
||||
{
|
||||
try
|
||||
{
|
||||
_javaFileStorage.Jfs.OnResume();
|
||||
return _javaFileStorage.Jfs.IsConnected;
|
||||
}
|
||||
catch (Java.Lang.Exception e)
|
||||
{
|
||||
throw _javaFileStorage.LogAndConvertJavaException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class JavaFileStorageWriteTransaction: IWriteTransaction
|
||||
{
|
||||
@ -255,13 +215,14 @@ namespace keepass2android.Io
|
||||
CanWrite = e.CanWrite,
|
||||
IsDirectory = e.IsDirectory,
|
||||
LastModified = JavaTimeToCSharp(e.LastModifiedTime),
|
||||
Path = Protocol + "://" + e.Path,
|
||||
Path = e.Path,
|
||||
SizeInBytes = e.SizeInBytes
|
||||
};
|
||||
}
|
||||
|
||||
public FileDescription GetFileDescription(IOConnectionInfo ioc)
|
||||
{
|
||||
Kp2aLog.Log("GetFileDescription "+ioc.Path);
|
||||
try
|
||||
{
|
||||
return ConvertToFileDescription(Jfs.GetFileEntry(IocToPath(ioc)));
|
||||
@ -276,24 +237,54 @@ namespace keepass2android.Io
|
||||
}
|
||||
}
|
||||
|
||||
public bool RequiresSetup(IOConnectionInfo ioConnection)
|
||||
{
|
||||
return _jfs.RequiresSetup(IocToPath(ioConnection));
|
||||
}
|
||||
|
||||
public void StartSelectFile(IFileStorageSetupInitiatorActivity activity, bool isForSave, int requestCode, string protocolId)
|
||||
{
|
||||
Kp2aLog.Log("StartSelectFile " + protocolId);
|
||||
_jfs.StartSelectFile((IJavaFileStorageFileStorageSetupInitiatorActivity) activity, isForSave, requestCode);
|
||||
}
|
||||
|
||||
public void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode)
|
||||
{
|
||||
_jfs.PrepareFileUsage((IJavaFileStorageFileStorageSetupInitiatorActivity)activity, IocToPath(ioc), requestCode);
|
||||
}
|
||||
|
||||
public void OnCreate(IFileStorageSetupActivity activity, Bundle savedInstanceState)
|
||||
{
|
||||
_jfs.OnCreate(((IJavaFileStorageFileStorageSetupActivity)activity), savedInstanceState);
|
||||
}
|
||||
|
||||
public void OnResume(IFileStorageSetupActivity activity)
|
||||
{
|
||||
Kp2aLog.Log("JFS/OnResume Ioc.Path=" +activity.Ioc.Path+". Path="+((IJavaFileStorageFileStorageSetupActivity)activity).Path);
|
||||
_jfs.OnResume(((IJavaFileStorageFileStorageSetupActivity) activity));
|
||||
}
|
||||
|
||||
public void OnStart(IFileStorageSetupActivity activity)
|
||||
{
|
||||
_jfs.OnStart(((IJavaFileStorageFileStorageSetupActivity) activity));
|
||||
}
|
||||
|
||||
public void OnActivityResult(IFileStorageSetupActivity activity, int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
_jfs.OnActivityResult(((IJavaFileStorageFileStorageSetupActivity) activity), requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
private DateTime JavaTimeToCSharp(long javatime)
|
||||
{
|
||||
//todo test
|
||||
return new DateTime(1970, 1, 1).AddMilliseconds(javatime);
|
||||
|
||||
}
|
||||
|
||||
private string IocToPath(IOConnectionInfo ioc)
|
||||
{
|
||||
if (ioc.Path.StartsWith(Protocol + "://"))
|
||||
return ioc.Path.Substring(Protocol.Length + 3);
|
||||
else
|
||||
public string IocToPath(IOConnectionInfo ioc)
|
||||
{
|
||||
return ioc.Path;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract string Protocol { get; }
|
||||
}
|
||||
#endif
|
||||
}
|
@ -20,7 +20,7 @@
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;EXCLUDE_JAVAFILESTORAGE</DefineConstants>
|
||||
<DefineConstants>TRACE;DEBUG;INCLUDE_TWOFISH;INCLUDE_KEYBOARD;INCLUDE_KEYTRANSFORM;INCLUDE_FILECHOOSER;INCLUDE_JAVAFILESTORAGE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
@ -58,7 +58,10 @@
|
||||
<Compile Include="Io\BuiltInFileStorage.cs" />
|
||||
<Compile Include="Io\CachingFileStorage.cs" />
|
||||
<Compile Include="Io\DropboxFileStorage.cs" />
|
||||
<Compile Include="Io\DropboxFileStorageKeys.cs" />
|
||||
<Compile Include="Io\FileDescription.cs" />
|
||||
<Compile Include="Io\FileStorageSetupActivity.cs" />
|
||||
<Compile Include="Io\FileStorageSetupInitiatorActivity.cs" />
|
||||
<Compile Include="Io\GDriveFileStorage.cs" />
|
||||
<Compile Include="Io\IFileStorage.cs" />
|
||||
<Compile Include="Io\IoUtil.cs" />
|
||||
@ -93,7 +96,7 @@
|
||||
<Compile Include="ProgressDialogStatusLogger.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj" Condition="!$(DefineConstants.Contains('EXCLUDE_JAVAFILESTORAGE'))">
|
||||
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj">
|
||||
<Project>{48574278-4779-4b3a-a9e4-9cf1bc285d0b}</Project>
|
||||
<Name>JavaFileStorageBindings</Name>
|
||||
</ProjectReference>
|
||||
|
@ -5,5 +5,7 @@
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<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.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"/>
|
||||
</classpath>
|
||||
|
@ -18,5 +18,6 @@
|
||||
|
||||
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
|
||||
|
||||
</manifest>
|
||||
|
@ -8,8 +8,9 @@
|
||||
# project structure.
|
||||
#
|
||||
# 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.
|
||||
target=android-17
|
||||
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.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.DropBoxManager.Entry;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
@ -35,7 +36,7 @@ import com.dropbox.client2.session.Session.AccessType;
|
||||
public class DropboxFileStorage implements JavaFileStorage {
|
||||
|
||||
//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
|
||||
|
||||
// If you'd like to change the access type to the full Dropbox instead of
|
||||
@ -52,8 +53,13 @@ public class DropboxFileStorage implements JavaFileStorage {
|
||||
private boolean mLoggedIn = false;
|
||||
private Context mContext;
|
||||
|
||||
public DropboxFileStorage(Context ctx)
|
||||
private String appKey;
|
||||
private String appSecret;
|
||||
|
||||
public DropboxFileStorage(Context ctx, String _appKey, String _appSecret)
|
||||
{
|
||||
appKey = _appKey;
|
||||
appSecret = _appSecret;
|
||||
mContext = ctx;
|
||||
// We create a new AuthSession so that we can use the Dropbox API.
|
||||
AndroidAuthSession session = buildSession();
|
||||
@ -62,6 +68,23 @@ public class DropboxFileStorage implements JavaFileStorage {
|
||||
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();
|
||||
}
|
||||
|
||||
public boolean tryConnect(Activity activity)
|
||||
{
|
||||
if (!mLoggedIn)
|
||||
@ -69,29 +92,6 @@ public class DropboxFileStorage implements JavaFileStorage {
|
||||
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) {
|
||||
mLoggedIn = b;
|
||||
|
||||
@ -101,7 +101,7 @@ public class DropboxFileStorage implements JavaFileStorage {
|
||||
|
||||
// Check if the app has set up its manifest properly.
|
||||
Intent testIntent = new Intent(Intent.ACTION_VIEW);
|
||||
String scheme = "db-" + APP_KEY;
|
||||
String scheme = "db-" + appKey;
|
||||
String uri = scheme + "://" + AuthActivity.AUTH_VERSION + "/test";
|
||||
testIntent.setData(Uri.parse(uri));
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
@ -123,9 +123,10 @@ public class DropboxFileStorage implements JavaFileStorage {
|
||||
|
||||
public boolean checkForFileChangeFast(String path, String previousFileVersion) throws Exception
|
||||
{
|
||||
if ((previousFileVersion == null) || (previousFileVersion == ""))
|
||||
if ((previousFileVersion == null) || (previousFileVersion.equals("")))
|
||||
return false;
|
||||
try {
|
||||
path = removeProtocol(path);
|
||||
com.dropbox.client2.DropboxAPI.Entry entry = mApi.metadata(path, 1, null, false, null);
|
||||
return entry.hash != previousFileVersion;
|
||||
} catch (DropboxException e) {
|
||||
@ -136,6 +137,7 @@ public class DropboxFileStorage implements JavaFileStorage {
|
||||
public String getCurrentFileVersionFast(String path)
|
||||
{
|
||||
try {
|
||||
path = removeProtocol(path);
|
||||
com.dropbox.client2.DropboxAPI.Entry entry = mApi.metadata(path, 1, null, false, null);
|
||||
return entry.rev;
|
||||
} catch (DropboxException e) {
|
||||
@ -147,6 +149,7 @@ public class DropboxFileStorage implements JavaFileStorage {
|
||||
public InputStream openFileForRead(String path) throws Exception
|
||||
{
|
||||
try {
|
||||
path = removeProtocol(path);
|
||||
return mApi.getFileStream(path, null);
|
||||
} catch (DropboxException e) {
|
||||
//System.out.println("Something went wrong: " + e);
|
||||
@ -158,6 +161,7 @@ public class DropboxFileStorage implements JavaFileStorage {
|
||||
{
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(data);
|
||||
try {
|
||||
path = removeProtocol(path);
|
||||
//TODO: it would be nice to be able to use the parent version with putFile()
|
||||
mApi.putFileOverwrite(path, bis, data.length, null);
|
||||
} catch (DropboxException e) {
|
||||
@ -231,7 +235,6 @@ public class DropboxFileStorage implements JavaFileStorage {
|
||||
edit.commit();
|
||||
}
|
||||
|
||||
//TODO: call when Unlinked Exception
|
||||
private void clearKeys() {
|
||||
SharedPreferences prefs = mContext.getSharedPreferences(ACCOUNT_PREFS_NAME, 0);
|
||||
Editor edit = prefs.edit();
|
||||
@ -240,8 +243,7 @@ public class DropboxFileStorage implements JavaFileStorage {
|
||||
}
|
||||
|
||||
private AndroidAuthSession buildSession() {
|
||||
//note: the SecretKeys class is not public because the App-Secret must be secret!
|
||||
AppKeyPair appKeyPair = new AppKeyPair(APP_KEY, SecretKeys.DROPBOX_APP_SECRET);
|
||||
AppKeyPair appKeyPair = new AppKeyPair(appKey, appSecret);
|
||||
AndroidAuthSession session;
|
||||
|
||||
String[] stored = getKeys();
|
||||
@ -263,6 +265,7 @@ public class DropboxFileStorage implements JavaFileStorage {
|
||||
public void createFolder(String path) throws Exception {
|
||||
try
|
||||
{
|
||||
path = removeProtocol(path);
|
||||
mApi.createFolder(path);
|
||||
}
|
||||
catch (DropboxException e) {
|
||||
@ -274,6 +277,7 @@ public class DropboxFileStorage implements JavaFileStorage {
|
||||
public List<FileEntry> listFiles(String dirName) throws Exception {
|
||||
try
|
||||
{
|
||||
dirName = removeProtocol(dirName);
|
||||
com.dropbox.client2.DropboxAPI.Entry dirEntry = mApi.metadata(dirName, 0, null, true, null);
|
||||
|
||||
if (dirEntry.isDeleted)
|
||||
@ -305,7 +309,7 @@ public class DropboxFileStorage implements JavaFileStorage {
|
||||
fileEntry.canWrite = true;
|
||||
fileEntry.isDirectory = e.isDir;
|
||||
fileEntry.sizeInBytes = e.bytes;
|
||||
fileEntry.path = e.path;
|
||||
fileEntry.path = getProtocolId()+"://"+ e.path;
|
||||
//Log.d("JFS","fileEntry="+fileEntry);
|
||||
Date lastModifiedDate = null;
|
||||
if (e.modified != null)
|
||||
@ -322,6 +326,7 @@ public class DropboxFileStorage implements JavaFileStorage {
|
||||
public void delete(String path) throws Exception {
|
||||
try
|
||||
{
|
||||
path = removeProtocol(path);
|
||||
mApi.delete(path);
|
||||
} catch (DropboxException e) {
|
||||
throw convertException(e);
|
||||
@ -334,8 +339,8 @@ public class DropboxFileStorage implements JavaFileStorage {
|
||||
public FileEntry getFileEntry(String filename) throws Exception {
|
||||
try
|
||||
{
|
||||
Log.d("JFS", "Hi!");
|
||||
Log.d("JFS", "mApi = "+mApi);
|
||||
filename = removeProtocol(filename);
|
||||
Log.d("KP2AJ", "getFileEntry(), mApi = "+mApi+" filename="+filename);
|
||||
com.dropbox.client2.DropboxAPI.Entry dbEntry = mApi.metadata(filename, 0, null, false, null);
|
||||
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 android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
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 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 boolean isConnected();
|
||||
//public void onActivityResult(Activity activity, final int requestCode, final int resultCode, final Intent data);
|
||||
|
||||
//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;
|
||||
|
||||
@ -88,4 +131,9 @@ public class FileEntry {
|
||||
|
||||
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
|
||||
|| !BaseFileProviderUtils.isDirectory(getActivity(), path))
|
||||
{
|
||||
Log.d(CLASSNAME, "load default path");
|
||||
path = BaseFileProviderUtils
|
||||
.getDefaultPath(
|
||||
getActivity(),
|
||||
path == null ? mFileProviderAuthority : path
|
||||
.getAuthority());
|
||||
}
|
||||
|
||||
if (path == null) {
|
||||
showCannotConnectToServiceAndFinish();
|
||||
|
@ -213,10 +213,7 @@ public class DisplayPrefs extends Prefs {
|
||||
* @since v4.7 beta
|
||||
*/
|
||||
public static boolean isRememberLastLocation(Context c) {
|
||||
return p(c).getBoolean(
|
||||
c.getString(R.string.afc_pkey_display_remember_last_location),
|
||||
c.getResources().getBoolean(
|
||||
R.bool.afc_pkey_display_remember_last_location_def));
|
||||
return false; //KP2A: don't allow to remember because of different protocols
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -13,7 +13,7 @@ public class Kp2aFileChooserBridge {
|
||||
Class<?> cls = FileChooserActivity.class;
|
||||
|
||||
Intent intent = new Intent(ctx, cls);
|
||||
|
||||
intent.putExtra(FileChooserActivity.EXTRA_FILE_PROVIDER_AUTHORITY, authority);
|
||||
intent.putExtra(FileChooserActivity.EXTRA_ROOTPATH,
|
||||
BaseFile.genContentIdUriBase(authority)
|
||||
.buildUpon()
|
||||
|
@ -230,7 +230,11 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
|
||||
private MatrixCursor doAnswerApiCommand(Uri uri) {
|
||||
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,
|
||||
BaseFile.PARAM_TASK_ID, 0);
|
||||
synchronized (mMapInterruption) {
|
||||
@ -241,15 +245,14 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
|
||||
mMapInterruption.put(taskId, true);
|
||||
}
|
||||
return null;
|
||||
} else if (BaseFile.CMD_GET_DEFAULT_PATH.equals(uri
|
||||
.getLastPathSegment())) {
|
||||
} else if (BaseFile.CMD_GET_DEFAULT_PATH.equals(lastPathSegment)) {
|
||||
|
||||
return null;
|
||||
|
||||
}// 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);
|
||||
} else if (BaseFile.CMD_GET_PARENT.equals(uri.getLastPathSegment())) {
|
||||
} else if (BaseFile.CMD_GET_PARENT.equals(lastPathSegment)) {
|
||||
|
||||
{
|
||||
String path = Uri.parse(
|
||||
@ -292,7 +295,7 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
|
||||
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
|
||||
* onDestroy(), it seems that this code block will be suspended and
|
||||
@ -492,6 +495,7 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
|
||||
|
||||
//puts the file entry in the cache for later reuse with retrieveFileInfo
|
||||
private void updateFileEntryCache(FileEntry 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
|
||||
@ -501,11 +505,17 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
|
||||
if (recursive)
|
||||
{
|
||||
Set<String> keys = fileEntryMap.keySet();
|
||||
Set<String> keysToRemove = new HashSet<String>();
|
||||
for (String key: keys)
|
||||
{
|
||||
if (key.startsWith(key))
|
||||
keysToRemove.add(key);
|
||||
}
|
||||
for (String key: keysToRemove)
|
||||
{
|
||||
fileEntryMap.remove(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,6 +22,7 @@ namespace keepass2android
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
|
||||
builder.SetTitle(ctx.GetString(Resource.String.ChangeLog_title));
|
||||
String[] changeLog = {
|
||||
ctx.GetString(Resource.String.ChangeLog_0_9),
|
||||
ctx.GetString(Resource.String.ChangeLog_0_8_6),
|
||||
ctx.GetString(Resource.String.ChangeLog_0_8_5),
|
||||
ctx.GetString(Resource.String.ChangeLog_0_8_4),
|
||||
|
@ -1,20 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Content.PM;
|
||||
using Android.Graphics.Drawables;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using KeePassLib;
|
||||
using KeePassLib.Keys;
|
||||
using KeePassLib.Security;
|
||||
using KeePassLib.Serialization;
|
||||
using keepass2android.Io;
|
||||
using keepass2android.view;
|
||||
using Object = Java.Lang.Object;
|
||||
@ -24,15 +14,17 @@ namespace keepass2android
|
||||
[Activity (Label = "@string/app_name", ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden , Theme="@style/NoTitleBar")]
|
||||
public class FileStorageSelectionActivity : ListActivity
|
||||
{
|
||||
private string _protocolToSetup;
|
||||
private FileStorageAdapter _fileStorageAdapter;
|
||||
|
||||
public const string AllowThirdPartyAppGet = "AllowThirdPartyAppGet";
|
||||
public const string AllowThirdPartyAppSend = "AllowThirdPartyAppSend";
|
||||
|
||||
class FileStorageAdapter: BaseAdapter
|
||||
{
|
||||
|
||||
private readonly FileStorageSelectionActivity _context;
|
||||
|
||||
private List<string> _protocolIds = new List<string>();
|
||||
private readonly List<string> _protocolIds = new List<string>();
|
||||
|
||||
public FileStorageAdapter(FileStorageSelectionActivity context)
|
||||
{
|
||||
@ -40,8 +32,13 @@ namespace keepass2android
|
||||
//show all supported protocols:
|
||||
foreach (IFileStorage fs in App.Kp2a.FileStorages)
|
||||
_protocolIds.AddRange(fs.SupportedProtocols);
|
||||
//except file://
|
||||
//put file:// to the top
|
||||
_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)
|
||||
@ -68,25 +65,8 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
private void OnItemSelected(string protocolId)
|
||||
{
|
||||
var fs = App.Kp2a.GetFileStorage(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);
|
||||
|
||||
if (bundle != null)
|
||||
_protocolToSetup = bundle.GetString("_protocolToSetup", null);
|
||||
|
||||
SetContentView(Resource.Layout.filestorage_selection);
|
||||
|
||||
_fileStorageAdapter = new FileStorageAdapter(this);
|
||||
this.ListAdapter = _fileStorageAdapter;
|
||||
ListAdapter = _fileStorageAdapter;
|
||||
|
||||
FindViewById<ListView>(Android.Resource.Id.List).ItemClick +=
|
||||
(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.Serialization;
|
||||
using KeePassLib.Utility;
|
||||
|
||||
using keepass2android.Io;
|
||||
using MemoryStream = System.IO.MemoryStream;
|
||||
|
||||
namespace keepass2android
|
||||
@ -189,6 +189,9 @@ namespace keepass2android
|
||||
}
|
||||
}
|
||||
break;
|
||||
case (Result)FileStorageResults.FileUsagePrepared:
|
||||
PeformLoadDatabase();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
@ -272,25 +275,10 @@ namespace keepass2android
|
||||
Window.SetSoftInputMode(SoftInput.StateVisible);
|
||||
|
||||
Button confirmButton = (Button)FindViewById(Resource.Id.pass_ok);
|
||||
confirmButton.Click += (sender, e) => {
|
||||
String pass = GetEditText(Resource.Id.password);
|
||||
String key = GetEditText(Resource.Id.pass_keyfile);
|
||||
if (pass.Length == 0 && key.Length == 0)
|
||||
confirmButton.Click += (sender, e) =>
|
||||
{
|
||||
ErrorMessage(Resource.String.error_nopass);
|
||||
return;
|
||||
}
|
||||
|
||||
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();
|
||||
App.Kp2a.GetFileStorage(_ioConnection)
|
||||
.PrepareFileUsage(new FileStorageSetupInitiatorActivity(this, OnActivityResult), _ioConnection, 0);
|
||||
};
|
||||
|
||||
/*CheckBox checkBox = (CheckBox) FindViewById(Resource.Id.show_password);
|
||||
@ -334,6 +322,32 @@ namespace keepass2android
|
||||
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()
|
||||
{
|
||||
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
|
||||
//performed in FileSelectActivity, but e.g. if the user unlinks from Dropbox saving might fail and
|
||||
//the user is returned here.
|
||||
if (App.Kp2a.GetFileStorage(_ioConnection).RequiredSetup != null)
|
||||
if (App.Kp2a.GetFileStorage(_ioConnection).RequiresSetup(_ioConnection))
|
||||
{
|
||||
GoToFileSelectActivity();
|
||||
}
|
||||
|
@ -1,6 +1,13 @@
|
||||
<?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" />
|
||||
|
||||
<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">
|
||||
<activity android:name="com.dropbox.client2.android.AuthActivity" android:launchMode="singleTask" android:configChanges="orientation|keyboard">
|
||||
<intent-filter>
|
||||
@ -13,7 +20,20 @@
|
||||
</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.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">
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
@ -54,4 +74,5 @@
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="keepass2android.keepass2android.permission.KP2aInternalFileBrowsing" />
|
||||
</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_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<keepass2android.view.FileSelectButtons
|
||||
android:id="@+id/file_select"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
<!-- 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_height="wrap_content"
|
||||
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"
|
||||
android:id="@+id/textView"
|
||||
android:layout_gravity="left|center_vertical"/>
|
||||
|
@ -27,6 +27,7 @@
|
||||
<string name="issues">http://keepass2android.codeplex.com</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="permission_desc">KP2A Internal File Browsing Permission</string>
|
||||
|
||||
<!-- Preference settings -->
|
||||
<string name="algorithm_key">algorithm</string>
|
||||
|
@ -320,16 +320,29 @@
|
||||
<string name="ok_donate">Tell me more!</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_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_http">HTTP (WebDav)</string>
|
||||
<string name="filestoragename_https">HTTPS (WebDav)</string>
|
||||
<string name="filestoragename_dropbox">Dropbox</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_0_8_6">
|
||||
<b>Version 0.8.6</b>\n
|
||||
* Support for Twofish cipher\n
|
||||
|
@ -20,6 +20,8 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Database;
|
||||
using Android.Provider;
|
||||
using Android.Widget;
|
||||
using Android.Content.PM;
|
||||
using Uri = Android.Net.Uri;
|
||||
@ -126,35 +128,36 @@ namespace keepass2android
|
||||
|
||||
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);
|
||||
i.SetType("file/*");
|
||||
|
||||
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
|
||||
{
|
||||
BrowserDialog diag = new BrowserDialog(act);
|
||||
diag.Show();
|
||||
string defaultPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
#if !EXCLUDE_FILECHOOSER
|
||||
@ -165,7 +168,25 @@ namespace keepass2android
|
||||
Uri uri = (Uri) uris[0];
|
||||
return Group.Pals.Android.Lib.UI.Filechooser.Providers.BaseFileProviderUtils.GetRealUri(ctx, uri).ToString();
|
||||
}
|
||||
|
||||
#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;
|
||||
if (String.IsNullOrEmpty(filename))
|
||||
|
@ -377,7 +377,7 @@ namespace keepass2android
|
||||
|
||||
}
|
||||
//TODO: catch!
|
||||
throw new Exception("Unknown protocol " + iocInfo);
|
||||
throw new Exception("Unknown protocol " + iocInfo.Path);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
Kp2aLog.Log("Provider.GetFileEntry " + filename);
|
||||
return ConvertFileDescription(App.Kp2a.GetFileStorage(filename).GetFileDescription(ConvertPathToIoc(filename)));
|
||||
}
|
||||
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,
|
||||
string negativeRegex, IList<FileEntry> fileList, bool[] hasMoreFiles)
|
||||
{
|
||||
Kp2aLog.Log("Provider.ListFiles " + dirName);
|
||||
try
|
||||
{
|
||||
var dirContents = App.Kp2a.GetFileStorage(dirName).ListContents(ConvertPathToIoc(dirName));
|
||||
|
@ -63,7 +63,6 @@ namespace keepass2android
|
||||
view.FileSelectButtons _fileSelectButtons;
|
||||
|
||||
internal AppTask AppTask;
|
||||
private IOConnectionInfo _iocToLaunch;
|
||||
|
||||
public const string NoForwardToPasswordActivity = "NoForwardToPasswordActivity";
|
||||
|
||||
@ -234,26 +233,18 @@ namespace keepass2android
|
||||
|
||||
EventHandler openFileButtonClick = (sender, e) =>
|
||||
{
|
||||
string defaultFilename = Android.OS.Environment.ExternalStorageDirectory + GetString(Resource.String.default_file_path);
|
||||
const string detailsText = "";
|
||||
ShowFilenameDialog(true, false, true, defaultFilename, detailsText, Intents.RequestCodeFileBrowseForOpen);
|
||||
|
||||
Intent intent = new Intent(this, typeof(FileStorageSelectionActivity));
|
||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, true);
|
||||
StartActivityForResult(intent, 0);
|
||||
|
||||
};
|
||||
openFileButton.Click += openFileButtonClick;
|
||||
//OPEN URL
|
||||
Button openUrlButton = (Button)FindViewById(Resource.Id.start_open_url);
|
||||
|
||||
#if NoNet
|
||||
openUrlButton.Visibility = ViewStates.Gone;
|
||||
#endif
|
||||
|
||||
//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
|
||||
Button createNewButton = (Button)FindViewById(Resource.Id.start_create);
|
||||
@ -282,20 +273,6 @@ namespace keepass2android
|
||||
{
|
||||
AppTask = AppTask.CreateFromBundle(savedInstanceState);
|
||||
_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);
|
||||
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 {
|
||||
@ -407,15 +377,6 @@ namespace keepass2android
|
||||
void LaunchPasswordActivityForIoc(IOConnectionInfo 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))
|
||||
{
|
||||
@ -485,9 +446,19 @@ namespace keepass2android
|
||||
if (resultCode == KeePass.ExitFileStorageSelectionOk)
|
||||
{
|
||||
#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
|
||||
Toast.MakeText(this, "TODO: make this more flexible.", ToastLength.Long).Show();
|
||||
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;
|
||||
}
|
||||
|
||||
//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();
|
||||
|
||||
@ -591,7 +573,7 @@ namespace keepass2android
|
||||
StartManagingCursor(filesCursor);
|
||||
filesCursor.MoveToFirst();
|
||||
IOConnectionInfo ioc = _DbHelper.CursorToIoc(filesCursor);
|
||||
if (App.Kp2a.GetFileStorage(ioc).RequiredSetup == null)
|
||||
if (App.Kp2a.GetFileStorage(ioc).RequiresSetup(ioc) == false)
|
||||
{
|
||||
LaunchPasswordActivityForIoc(ioc);
|
||||
}
|
||||
@ -684,6 +666,10 @@ namespace keepass2android
|
||||
Android.Database.ICursor cursor = ca.Cursor;
|
||||
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>
|
||||
<Optimize>False</Optimize>
|
||||
<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>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>False</ConsolePause>
|
||||
@ -79,6 +79,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="fileselect\FileChooserFileProvider.cs" />
|
||||
<Compile Include="fileselect\FileStorageSetupActivity.cs" />
|
||||
<Compile Include="fileselect\FileStorageSetupInitiatorActivity.cs" />
|
||||
<Compile Include="FileStorageSelectionActivity.cs" />
|
||||
<Compile Include="DonateReminder.cs" />
|
||||
<Compile Include="app\ApplicationBroadcastReceiver.cs" />
|
||||
@ -96,7 +98,6 @@
|
||||
<Compile Include="settings\DatabaseSettingsActivity.cs" />
|
||||
<Compile Include="Utils\Util.cs" />
|
||||
<Compile Include="intents\Intents.cs" />
|
||||
<Compile Include="fileselect\BrowserDialog.cs" />
|
||||
<Compile Include="timeout\TimeoutHelper.cs" />
|
||||
<Compile Include="GroupActivity.cs" />
|
||||
<Compile Include="GroupBaseActivity.cs" />
|
||||
@ -816,4 +817,28 @@
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\ic_storage_http.png" />
|
||||
</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>
|