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

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

View File

@ -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>
@ -155,7 +155,7 @@
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
<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>
<Name>kp2akeytransform</Name>
</ProjectReference>

View File

@ -2,16 +2,9 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using KeePassLib.Serialization;
using KeePassLib.Utility;
@ -89,8 +82,6 @@ namespace keepass2android.Io
return new BuiltInFileTransaction(ioc, useFileTransaction);
}
public IFileStorageSetup RequiredSetup { get { return null; } }
public class BuiltInFileTransaction : IWriteTransaction
{
private readonly FileTransactionEx _transaction;
@ -155,5 +146,54 @@ namespace keepass2android.Io
//TODO
throw new NotImplementedException();
}
public bool RequiresSetup(IOConnectionInfo ioConnection)
{
return false;
}
public string IocToPath(IOConnectionInfo ioc)
{
return ioc.Path;
}
public void StartSelectFile(IFileStorageSetupInitiatorActivity activity, bool isForSave, int requestCode, string protocolId)
{
if (protocolId != "file")
activity.PerformManualFileSelect(isForSave, requestCode, protocolId);
else
{
Intent intent = new Intent();
activity.IocToIntent(intent, new IOConnectionInfo() { Path = protocolId+"://"});
activity.OnImmediateResult(requestCode, (int) FileStorageResults.FileChooserPrepared, intent);
}
}
public void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode)
{
Intent intent = new Intent();
activity.IocToIntent(intent, ioc);
activity.OnImmediateResult(requestCode, (int) FileStorageResults.FileUsagePrepared, intent);
}
public void OnCreate(IFileStorageSetupActivity activity, Bundle savedInstanceState)
{
throw new NotImplementedException();
}
public void OnResume(IFileStorageSetupActivity activity)
{
throw new NotImplementedException();
}
public void OnStart(IFileStorageSetupActivity activity)
{
throw new NotImplementedException();
}
public void OnActivityResult(IFileStorageSetupActivity activity, int requestCode, int resultCode, Intent data)
{
throw new NotImplementedException();
}
}
}

View File

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

View File

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

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using KeePassLib.Serialization;
namespace keepass2android.Io
{
public interface IFileStorageSetupActivity
{
IOConnectionInfo Ioc { get; }
String ProcessName { get; }
bool IsForSave { get; }
Bundle State { get; }
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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>

View File

@ -18,5 +18,6 @@
</application>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
</manifest>

View File

@ -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

View File

@ -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
@ -51,14 +52,36 @@ public class DropboxFileStorage implements JavaFileStorage {
DropboxAPI<AndroidAuthSession> mApi;
private boolean mLoggedIn = false;
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;
// We create a new AuthSession so that we can use the Dropbox API.
AndroidAuthSession session = buildSession();
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();
}
@ -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);
}
}

View File

@ -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
}
}
*/

View File

@ -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 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;
@ -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);
}

View File

@ -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();

View File

@ -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
}
/**

View File

@ -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()

View File

@ -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,7 +495,8 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
//puts the file entry in the cache for later reuse with retrieveFileInfo
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
private void removeFromCache(String filename, boolean recursive) {
@ -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))
fileEntryMap.remove(key);
keysToRemove.add(key);
}
for (String key: keysToRemove)
{
fileEntryMap.remove(key);
}
}

View File

@ -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),

View File

@ -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)
@ -69,24 +66,7 @@ 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();
}
ReturnProtocol(protocolId);
}
@ -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();
}
}
}
}
}

View File

@ -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,26 +275,11 @@ 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);
// Show or hide 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();
}

View File

@ -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>

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -8,13 +8,16 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal">
<ScrollView
<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" />
<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 -->

View File

@ -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"/>

View File

@ -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>

View File

@ -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_title">Change log</string>
<string name="ChangeLog_0_8_6">
<b>Version 0.8.6</b>\n
* Support for Twofish cipher\n

View File

@ -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))

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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));

View File

@ -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();
}
}
}

View 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; }
}
}

View File

@ -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);
}
}
}

View File

@ -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" />
@ -253,7 +254,7 @@
<None Include="Resources\values-vi\strings.xml">
<Visible>False</Visible>
</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>
</None>
<None Include="Resources\drawable-hdpi\Thumbs.db">
@ -700,11 +701,11 @@
</MonoDevelop>
</ProjectExtensions>
<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>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</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>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</AndroidNativeLibrary>
@ -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>