Plugins: transferring list of protected fields
CreateDatabaseActivity: Passing app task to next activity Keepass.cs: added documentation on Activities and AppTasks SearchActivity.cs: passing appTask to next activity, using ForwardResult to pass ActivityResult back to previous activity FileSelectActivity: pass AppTask to CreateDatabaseActivity, Recreate instead of Start+Finish (to have correct handling of ActivityResults)
This commit is contained in:
@@ -67,6 +67,7 @@
|
|||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="TestIntentsAndBundles.cs" />
|
||||||
<Compile Include="ProgressDialogStub.cs" />
|
<Compile Include="ProgressDialogStub.cs" />
|
||||||
<Compile Include="TestBase.cs" />
|
<Compile Include="TestBase.cs" />
|
||||||
<Compile Include="TestCacheSupervisor.cs" />
|
<Compile Include="TestCacheSupervisor.cs" />
|
||||||
@@ -85,6 +86,7 @@
|
|||||||
<Compile Include="TestSynchronizeCachedDatabase.cs" />
|
<Compile Include="TestSynchronizeCachedDatabase.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<None Include="ClassDiagram1.cd" />
|
||||||
<None Include="Resources\AboutResources.txt" />
|
<None Include="Resources\AboutResources.txt" />
|
||||||
<None Include="Assets\AboutAssets.txt" />
|
<None Include="Assets\AboutAssets.txt" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ namespace Kp2aUnitTests
|
|||||||
{
|
{
|
||||||
TestRunner runner = new TestRunner();
|
TestRunner runner = new TestRunner();
|
||||||
// Run all tests from this assembly
|
// Run all tests from this assembly
|
||||||
runner.AddTests(Assembly.GetExecutingAssembly());
|
//runner.AddTests(Assembly.GetExecutingAssembly());
|
||||||
|
runner.AddTests(new List<Type> { typeof(TestIntentsAndBundles) });
|
||||||
//runner.AddTests(new List<Type> { typeof(TestSynchronizeCachedDatabase)});
|
//runner.AddTests(new List<Type> { typeof(TestSynchronizeCachedDatabase)});
|
||||||
//runner.AddTests(typeof(TestLoadDb).GetMethod("LoadErrorWithCertificateTrustFailure"));
|
//runner.AddTests(typeof(TestLoadDb).GetMethod("LoadErrorWithCertificateTrustFailure"));
|
||||||
//runner.AddTests(typeof(TestLoadDb).GetMethod("LoadWithAcceptedCertificateTrustFailure"));
|
//runner.AddTests(typeof(TestLoadDb).GetMethod("LoadWithAcceptedCertificateTrustFailure"));
|
||||||
|
|||||||
@@ -152,10 +152,15 @@ namespace keepass2android
|
|||||||
//add the output string array (placeholders replaced taking into account the db context)
|
//add the output string array (placeholders replaced taking into account the db context)
|
||||||
Dictionary<string, string> outputFields = entry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key), pair => pair.Value.ReadString());
|
Dictionary<string, string> outputFields = entry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key), pair => pair.Value.ReadString());
|
||||||
|
|
||||||
|
//add field values as JSON ({ "key":"value", ... } form)
|
||||||
JSONObject json = new JSONObject(outputFields);
|
JSONObject json = new JSONObject(outputFields);
|
||||||
var jsonStr = json.ToString();
|
var jsonStr = json.ToString();
|
||||||
intent.PutExtra(Strings.ExtraEntryOutputData, jsonStr);
|
intent.PutExtra(Strings.ExtraEntryOutputData, jsonStr);
|
||||||
|
|
||||||
|
//add list of which fields are protected (StringArrayExtra)
|
||||||
|
string[] protectedFieldsList = entry.OutputStrings.Where(s=>s.Value.IsProtected).Select(s => s.Key).ToArray();
|
||||||
|
intent.PutExtra(Strings.ExtraProtectedFieldsList, protectedFieldsList);
|
||||||
|
|
||||||
intent.PutExtra(Strings.ExtraEntryId, entry.Uuid.ToHexString());
|
intent.PutExtra(Strings.ExtraEntryId, entry.Uuid.ToHexString());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,12 @@ public abstract class PluginActionBroadcastReceiver extends BroadcastReceiver {
|
|||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String[] getProtectedFieldsListFromIntent()
|
||||||
|
{
|
||||||
|
return _intent.getStringArrayExtra(Strings.EXTRA_PROTECTED_FIELDS_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class ActionSelected extends PluginActionBase
|
protected class ActionSelected extends PluginActionBase
|
||||||
@@ -89,10 +95,23 @@ public abstract class PluginActionBroadcastReceiver extends BroadcastReceiver {
|
|||||||
return getFieldId() == null;
|
return getFieldId() == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return a hashmap containing the entry fields in key/value form
|
||||||
|
*/
|
||||||
public HashMap<String, String> getEntryFields()
|
public HashMap<String, String> getEntryFields()
|
||||||
{
|
{
|
||||||
return getEntryFieldsFromIntent();
|
return getEntryFieldsFromIntent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return an array with the keys of all protected fields in the entry
|
||||||
|
*/
|
||||||
|
public String[] getProtectedFieldsList()
|
||||||
|
{
|
||||||
|
return getProtectedFieldsListFromIntent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class CloseEntryView extends PluginActionBase
|
protected class CloseEntryView extends PluginActionBase
|
||||||
@@ -125,6 +144,15 @@ public abstract class PluginActionBroadcastReceiver extends BroadcastReceiver {
|
|||||||
return getEntryFieldsFromIntent();
|
return getEntryFieldsFromIntent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return an array with the keys of all protected fields in the entry
|
||||||
|
*/
|
||||||
|
public String[] getProtectedFieldsList()
|
||||||
|
{
|
||||||
|
return getProtectedFieldsListFromIntent();
|
||||||
|
}
|
||||||
|
|
||||||
public void addEntryAction(String actionDisplayText, int actionIconResourceId, Bundle actionData) throws PluginAccessException
|
public void addEntryAction(String actionDisplayText, int actionIconResourceId, Bundle actionData) throws PluginAccessException
|
||||||
{
|
{
|
||||||
addEntryFieldAction(null, null, actionDisplayText, actionIconResourceId, actionData);
|
addEntryFieldAction(null, null, actionDisplayText, actionIconResourceId, actionData);
|
||||||
|
|||||||
@@ -88,6 +88,12 @@ public class Strings {
|
|||||||
*/
|
*/
|
||||||
public static final String EXTRA_ENTRY_OUTPUT_DATA = "keepass2android.EXTRA_ENTRY_OUTPUT_DATA";
|
public static final String EXTRA_ENTRY_OUTPUT_DATA = "keepass2android.EXTRA_ENTRY_OUTPUT_DATA";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Json serialized lisf of field keys, specifying which field of the EXTRA_ENTRY_OUTPUT_DATA is protected.
|
||||||
|
*/
|
||||||
|
public static final String EXTRA_PROTECTED_FIELDS_LIST = "keepass2android.EXTRA_PROTECTED_FIELDS_LIST";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extra key for passing the access token (both ways)
|
* Extra key for passing the access token (both ways)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ namespace keepass2android
|
|||||||
private bool _restoringInstanceState;
|
private bool _restoringInstanceState;
|
||||||
private bool _showPassword;
|
private bool _showPassword;
|
||||||
|
|
||||||
private ActivityDesign _design;
|
private readonly ActivityDesign _design;
|
||||||
|
private AppTask _appTask;
|
||||||
|
|
||||||
public CreateDatabaseActivity()
|
public CreateDatabaseActivity()
|
||||||
{
|
{
|
||||||
@@ -57,7 +58,7 @@ namespace keepass2android
|
|||||||
_design.ApplyTheme();
|
_design.ApplyTheme();
|
||||||
|
|
||||||
SetContentView(Resource.Layout.create_database);
|
SetContentView(Resource.Layout.create_database);
|
||||||
|
_appTask = AppTask.GetTaskInOnCreate(bundle, Intent);
|
||||||
|
|
||||||
SetDefaultIoc();
|
SetDefaultIoc();
|
||||||
|
|
||||||
@@ -527,7 +528,7 @@ namespace keepass2android
|
|||||||
dbHelper.CreateFile(_ioc, Filename);
|
dbHelper.CreateFile(_ioc, Filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupActivity.Launch(_activity, new NullTask());
|
GroupActivity.Launch(_activity, _activity._appTask);
|
||||||
_activity.Finish();
|
_activity.Finish();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,7 +127,9 @@ namespace keepass2android
|
|||||||
|
|
||||||
public override bool OnSearchRequested()
|
public override bool OnSearchRequested()
|
||||||
{
|
{
|
||||||
StartActivityForResult(typeof(SearchActivity), 0);
|
Intent i = new Intent(this, typeof(SearchActivity));
|
||||||
|
AppTask.ToIntent(i);
|
||||||
|
StartActivityForResult(i, 0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,36 +216,10 @@ namespace keepass2android
|
|||||||
titleText = GetText(Resource.String.root);
|
titleText = GetText(Resource.String.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
//see if the button for SDK Version < 11 is there
|
|
||||||
Button tv = (Button)FindViewById(Resource.Id.group_name);
|
|
||||||
if (tv != null)
|
|
||||||
{
|
|
||||||
if (Group != null)
|
|
||||||
{
|
|
||||||
tv.Text = titleText;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clickable)
|
|
||||||
{
|
|
||||||
tv.Click += (sender, e) =>
|
|
||||||
{
|
|
||||||
AppTask.SetActivityResult(this, KeePass.ExitNormal);
|
|
||||||
Finish();
|
|
||||||
};
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
tv.SetCompoundDrawables(null, null, null, null);
|
|
||||||
tv.Clickable = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//ICS?
|
|
||||||
if (Util.HasActionBar(this))
|
|
||||||
{
|
|
||||||
ActionBar.Title = titleText;
|
ActionBar.Title = titleText;
|
||||||
if (clickable)
|
if (clickable)
|
||||||
ActionBar.SetDisplayHomeAsUpEnabled(true);
|
ActionBar.SetDisplayHomeAsUpEnabled(true);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void SetGroupIcon() {
|
protected void SetGroupIcon() {
|
||||||
@@ -257,6 +233,29 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SuggestionListener: Java.Lang.Object, SearchView.IOnSuggestionListener
|
||||||
|
{
|
||||||
|
private readonly CursorAdapter _suggestionsAdapter;
|
||||||
|
|
||||||
|
public SuggestionListener(CursorAdapter suggestionsAdapter)
|
||||||
|
{
|
||||||
|
_suggestionsAdapter = suggestionsAdapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnSuggestionClick(int position)
|
||||||
|
{
|
||||||
|
var cursor = _suggestionsAdapter.Cursor;
|
||||||
|
cursor.MoveToPosition(position);
|
||||||
|
var x = cursor.GetString(cursor.GetColumnIndexOrThrow(SearchManager.SuggestColumnIntentDataId));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnSuggestionSelect(int position)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override bool OnCreateOptionsMenu(IMenu menu) {
|
public override bool OnCreateOptionsMenu(IMenu menu) {
|
||||||
base.OnCreateOptionsMenu(menu);
|
base.OnCreateOptionsMenu(menu);
|
||||||
|
|
||||||
@@ -268,6 +267,7 @@ namespace keepass2android
|
|||||||
var searchView = (SearchView) menu.FindItem(Resource.Id.menu_search).ActionView;
|
var searchView = (SearchView) menu.FindItem(Resource.Id.menu_search).ActionView;
|
||||||
|
|
||||||
searchView.SetSearchableInfo(searchManager.GetSearchableInfo(ComponentName));
|
searchView.SetSearchableInfo(searchManager.GetSearchableInfo(ComponentName));
|
||||||
|
searchView.SetOnSuggestionListener(new SuggestionListener(searchView.SuggestionsAdapter));
|
||||||
}
|
}
|
||||||
var item = menu.FindItem(Resource.Id.menu_sync);
|
var item = menu.FindItem(Resource.Id.menu_sync);
|
||||||
if (item != null)
|
if (item != null)
|
||||||
|
|||||||
@@ -28,6 +28,39 @@ using Java.Lang.Reflect;
|
|||||||
using KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
using Exception = System.Exception;
|
using Exception = System.Exception;
|
||||||
using String = System.String;
|
using String = System.String;
|
||||||
|
/**
|
||||||
|
* General documentation
|
||||||
|
*
|
||||||
|
* Activity stack and activity results
|
||||||
|
* ===================================
|
||||||
|
*
|
||||||
|
* Keepass2Android comprises quite a number of different activities and entry points: The app can be started
|
||||||
|
* using the launcher icon (-> Activity "Keepass"), or by sending a URL (-> FileSelect), opening a .kdb(x)-file (->Password),
|
||||||
|
* swiping a YubikeyNEO (NfcOtpActivity).
|
||||||
|
* While the database is closed, there is only one activity on the stack: Keepass -> FileSelect <-> Password.
|
||||||
|
* After opening an database (in Password), Password is always the root of the stack (exception: after creating a database,
|
||||||
|
* FileSelect is the root without Password being open).
|
||||||
|
*
|
||||||
|
* Some possible stacks:
|
||||||
|
* Password -> Group ( -> Group (subgroups) ... ) -> EntryView -> EntryEdit
|
||||||
|
* (AdvancedSearch Menu) -> Search -> SearchResults -> EntryView -> EntryEdit
|
||||||
|
* (SearchWidget) -> SearchResults -> EntryView -> EntryEdit
|
||||||
|
* Password -> ShareUrlResults -> EntryView
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* In each of these activities, an AppTask may be present and must be passed to started activities and ActivityResults
|
||||||
|
* must be returned. Therefore, if any Activity calls { StartActivity(newActivity);Finish(); }, it must specify FLAG_ACTIVITY_FORWARD_RESULT.
|
||||||
|
*
|
||||||
|
* Further sub-activities may be opened (e.g. Settings -> ExportDb, ...), but these are not necesarrily
|
||||||
|
* part of the AppTask. Then, neither the task has to be passed nor must the sub-activity return an ActivityResult.
|
||||||
|
*
|
||||||
|
* Activities with AppTasks should check if they get a new AppTask in OnActivityResult.
|
||||||
|
*
|
||||||
|
* Note: Chrome fires the ActionSend (Share URL) intent with NEW_TASK (i.e. KP2A appears in a separate task, either a new one,
|
||||||
|
* or, if it was running before, in the KP2A task), whereas Firefox doesn't specify that flag and KP2A appears "inside" Firefox.
|
||||||
|
* This means that the AppTask must be cleared for use in Chrome after finding an entry or pressing back button in ShareUrlResults.
|
||||||
|
* This would not be necessary for Firefox where the (Android) Task of standalone KP2A is not affected by the search.
|
||||||
|
*/
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -115,10 +115,10 @@ namespace keepass2android
|
|||||||
|
|
||||||
private class LockCloseActivityBroadcastReceiver : BroadcastReceiver
|
private class LockCloseActivityBroadcastReceiver : BroadcastReceiver
|
||||||
{
|
{
|
||||||
readonly LockCloseActivity _service;
|
readonly LockCloseActivity _activity;
|
||||||
public LockCloseActivityBroadcastReceiver(LockCloseActivity service)
|
public LockCloseActivityBroadcastReceiver(LockCloseActivity activity)
|
||||||
{
|
{
|
||||||
_service = service;
|
_activity = activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnReceive(Context context, Intent intent)
|
public override void OnReceive(Context context, Intent intent)
|
||||||
@@ -126,7 +126,7 @@ namespace keepass2android
|
|||||||
switch (intent.Action)
|
switch (intent.Action)
|
||||||
{
|
{
|
||||||
case Intents.DatabaseLocked:
|
case Intents.DatabaseLocked:
|
||||||
_service.OnLockDatabase();
|
_activity.OnLockDatabase();
|
||||||
break;
|
break;
|
||||||
case Intent.ActionScreenOff:
|
case Intent.ActionScreenOff:
|
||||||
App.Kp2a.OnScreenOff();
|
App.Kp2a.OnScreenOff();
|
||||||
|
|||||||
@@ -95,10 +95,10 @@ namespace keepass2android
|
|||||||
|
|
||||||
private class LockCloseListActivityBroadcastReceiver : BroadcastReceiver
|
private class LockCloseListActivityBroadcastReceiver : BroadcastReceiver
|
||||||
{
|
{
|
||||||
readonly LockCloseListActivity _service;
|
readonly LockCloseListActivity _activity;
|
||||||
public LockCloseListActivityBroadcastReceiver(LockCloseListActivity service)
|
public LockCloseListActivityBroadcastReceiver(LockCloseListActivity activity)
|
||||||
{
|
{
|
||||||
_service = service;
|
_activity = activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnReceive(Context context, Intent intent)
|
public override void OnReceive(Context context, Intent intent)
|
||||||
@@ -106,7 +106,7 @@ namespace keepass2android
|
|||||||
switch (intent.Action)
|
switch (intent.Action)
|
||||||
{
|
{
|
||||||
case Intents.DatabaseLocked:
|
case Intents.DatabaseLocked:
|
||||||
_service.OnLockDatabase();
|
_activity.OnLockDatabase();
|
||||||
break;
|
break;
|
||||||
case Intent.ActionScreenOff:
|
case Intent.ActionScreenOff:
|
||||||
App.Kp2a.OnScreenOff();
|
App.Kp2a.OnScreenOff();
|
||||||
|
|||||||
@@ -5831,7 +5831,10 @@ namespace keepass2android
|
|||||||
public const int searchable = 2131034140;
|
public const int searchable = 2131034140;
|
||||||
|
|
||||||
// aapt resource value: 0x7f05001d
|
// aapt resource value: 0x7f05001d
|
||||||
public const int searchable_offline = 2131034141;
|
public const int searchable_debug = 2131034141;
|
||||||
|
|
||||||
|
// aapt resource value: 0x7f05001e
|
||||||
|
public const int searchable_offline = 2131034142;
|
||||||
|
|
||||||
static Xml()
|
static Xml()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -62,27 +62,12 @@ namespace keepass2android
|
|||||||
SetResult(KeePass.ExitCloseAfterTaskComplete);
|
SetResult(KeePass.ExitCloseAfterTaskComplete);
|
||||||
|
|
||||||
_db = App.Kp2a.GetDb();
|
_db = App.Kp2a.GetDb();
|
||||||
|
if (App.Kp2a.DatabaseIsUnlocked)
|
||||||
|
{
|
||||||
String searchUrl = ((SearchUrlTask)AppTask).UrlToSearchFor;
|
String searchUrl = ((SearchUrlTask)AppTask).UrlToSearchFor;
|
||||||
|
|
||||||
if (!_db.Loaded)
|
|
||||||
{
|
|
||||||
Intent intent = new Intent(this, typeof(FileSelectActivity));
|
|
||||||
AppTask.ToIntent(intent);
|
|
||||||
intent.AddFlags(ActivityFlags.ClearTask | ActivityFlags.NewTask);
|
|
||||||
StartActivityForResult(intent, 0);
|
|
||||||
|
|
||||||
Finish();
|
|
||||||
}
|
|
||||||
else if (App.Kp2a.QuickLocked)
|
|
||||||
{
|
|
||||||
PasswordActivity.Launch(this,_db.Ioc, AppTask);
|
|
||||||
Finish();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Query(searchUrl);
|
Query(searchUrl);
|
||||||
}
|
}
|
||||||
|
// else: LockCloseListActivity.OnResume will trigger a broadcast (LockDatabase) which will cause the activity to be finished.
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +85,6 @@ namespace keepass2android
|
|||||||
|
|
||||||
private void Query(String url)
|
private void Query(String url)
|
||||||
{
|
{
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//first: search for exact url
|
//first: search for exact url
|
||||||
|
|||||||
@@ -323,6 +323,12 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void FinishAndForward(Activity activity, Intent i)
|
||||||
|
{
|
||||||
|
i.SetFlags(ActivityFlags.ForwardResult);
|
||||||
|
activity.StartActivity(i);
|
||||||
|
activity.Finish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,15 +67,17 @@ namespace keepass2android
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
public const int AppNameResource = Resource.String.app_name;
|
public const int AppNameResource = Resource.String.app_name;
|
||||||
public const string AppNameShort = "@string/short_app_name";
|
public const string AppNameShort = "@string/short_app_name" + "DBG";
|
||||||
public const string AppLauncherTitle = "@string/app_name";
|
public const string AppLauncherTitle = "@string/app_name" + " Debug";
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
public const string PackagePart = "keepass2android_debug";
|
public const string PackagePart = "keepass2android_debug";
|
||||||
|
public const string Searchable = "@xml/searchable_debug";
|
||||||
#else
|
#else
|
||||||
public const string PackagePart = "keepass2android";
|
public const string PackagePart = "keepass2android";
|
||||||
|
public const string Searchable = "@xml/searchable";
|
||||||
#endif
|
#endif
|
||||||
public const int LauncherIcon = Resource.Drawable.ic_launcher;
|
public const int LauncherIcon = Resource.Drawable.ic_launcher;
|
||||||
public const string Searchable = "@xml/searchable";
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -48,6 +48,29 @@ namespace keepass2android
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// represents data stored in an intent or bundle as extra string array
|
||||||
|
/// </summary>
|
||||||
|
public class StringArrayExtra : IExtra
|
||||||
|
{
|
||||||
|
public string Key { get; set; }
|
||||||
|
public string[] Value { get; set; }
|
||||||
|
|
||||||
|
#region IExtra implementation
|
||||||
|
|
||||||
|
public void ToBundle(Bundle b)
|
||||||
|
{
|
||||||
|
b.PutStringArray(Key, Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ToIntent(Intent i)
|
||||||
|
{
|
||||||
|
i.PutExtra(Key, Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// base class for "tasks": these are things the user wants to do and which require several activities
|
/// base class for "tasks": these are things the user wants to do and which require several activities
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -271,8 +294,20 @@ namespace keepass2android
|
|||||||
public override void AfterUnlockDatabase(PasswordActivity act)
|
public override void AfterUnlockDatabase(PasswordActivity act)
|
||||||
{
|
{
|
||||||
ShareUrlResults.Launch(act, this);
|
ShareUrlResults.Launch(act, this);
|
||||||
RemoveTaskFromIntent(act);
|
|
||||||
act.AppTask = new NullTask();
|
//removed. this causes an issue in the following workflow:
|
||||||
|
//When the user wants to find an entry for a URL but has the wrong database open he needs
|
||||||
|
//to switch to another database. But the Task is removed already the first time when going through PasswordActivity
|
||||||
|
// (with the wrong db).
|
||||||
|
//Then after switching to the right database, the task is gone.
|
||||||
|
|
||||||
|
//A reason this code existed was the following workflow:
|
||||||
|
//Using Chrome browser (with NEW_TASK flag for ActionSend): Share URL -> KP2A.
|
||||||
|
//Now the AppTask was in PasswordActivity and didn't get out of it.
|
||||||
|
//This is now solved by returning new tasks in ActivityResult.
|
||||||
|
|
||||||
|
//RemoveTaskFromIntent(act);
|
||||||
|
//act.AppTask = new NullTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CloseEntryActivityAfterCreate
|
public override bool CloseEntryActivityAfterCreate
|
||||||
@@ -393,30 +428,72 @@ namespace keepass2android
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class CreateEntryThenCloseTask: AppTask
|
public class CreateEntryThenCloseTask: AppTask
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// extra key if only a URL is passed. optional.
|
||||||
|
/// </summary>
|
||||||
public const String UrlKey = "CreateEntry_Url";
|
public const String UrlKey = "CreateEntry_Url";
|
||||||
|
|
||||||
public string Url
|
/// <summary>
|
||||||
{
|
/// extra key if a json serialized key/value mapping is passed. optional.
|
||||||
get;
|
/// </summary>
|
||||||
set;
|
/// Uses the PluginSDKs keys because this is mainly used for communicating with plugins.
|
||||||
}
|
/// Of course the data might also contain "non-output-data" (e.g. placeholders), but usually won't.
|
||||||
|
public const String AllFieldsKey = Keepass2android.Pluginsdk.Strings.ExtraEntryOutputData;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// extra key to specify a list of protected field keys in AllFieldsKey. Passed as StringArrayExtra. optional.
|
||||||
|
/// </summary>
|
||||||
|
public const String ProtectedFieldsListKey = Keepass2android.Pluginsdk.Strings.ExtraProtectedFieldsList;
|
||||||
|
|
||||||
|
public string Url { get; set; }
|
||||||
|
|
||||||
|
public string AllFields { get; set; }
|
||||||
|
|
||||||
|
public string[] ProtectedFieldsList { get; set; }
|
||||||
|
|
||||||
public override void Setup(Bundle b)
|
public override void Setup(Bundle b)
|
||||||
{
|
{
|
||||||
Url = b.GetString(UrlKey);
|
Url = b.GetString(UrlKey);
|
||||||
|
AllFields = b.GetString(AllFieldsKey);
|
||||||
|
ProtectedFieldsList = b.GetStringArray(ProtectedFieldsListKey);
|
||||||
}
|
}
|
||||||
public override IEnumerable<IExtra> Extras
|
public override IEnumerable<IExtra> Extras
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
if (Url != null)
|
||||||
yield return new StringExtra { Key = UrlKey, Value = Url };
|
yield return new StringExtra { Key = UrlKey, Value = Url };
|
||||||
|
if (AllFields != null)
|
||||||
|
yield return new StringExtra { Key = AllFieldsKey, Value = AllFields };
|
||||||
|
if (ProtectedFieldsList != null)
|
||||||
|
yield return new StringArrayExtra { Key = ProtectedFieldsListKey, Value = ProtectedFieldsList };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void PrepareNewEntry(PwEntry newEntry)
|
public override void PrepareNewEntry(PwEntry newEntry)
|
||||||
|
{
|
||||||
|
if (Url != null)
|
||||||
{
|
{
|
||||||
newEntry.Strings.Set(PwDefs.UrlField, new ProtectedString(false, Url));
|
newEntry.Strings.Set(PwDefs.UrlField, new ProtectedString(false, Url));
|
||||||
|
}
|
||||||
|
if (AllFields != null)
|
||||||
|
{
|
||||||
|
IList<string> protectedFieldsKeys = new List<string>();
|
||||||
|
if (ProtectedFieldsList != null)
|
||||||
|
{
|
||||||
|
protectedFieldsKeys = new Org.Json.JSONArray(ProtectedFieldsList).ToArray<string>();
|
||||||
|
}
|
||||||
|
var allFields = new Org.Json.JSONObject(AllFields);
|
||||||
|
for (var iter = allFields.Keys(); iter.HasNext; )
|
||||||
|
{
|
||||||
|
string key = iter.Next().ToString();
|
||||||
|
string value = allFields.Get(key).ToString();
|
||||||
|
bool isProtected = protectedFieldsKeys.Contains(key) || key == PwDefs.PasswordField;
|
||||||
|
newEntry.Strings.Set(key, new ProtectedString(isProtected, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ namespace keepass2android
|
|||||||
DataMimeType="text/plain")]
|
DataMimeType="text/plain")]
|
||||||
public class FileSelectActivity : ListActivity
|
public class FileSelectActivity : ListActivity
|
||||||
{
|
{
|
||||||
private ActivityDesign _design;
|
private readonly ActivityDesign _design;
|
||||||
public FileSelectActivity (IntPtr javaReference, JniHandleOwnership transfer)
|
public FileSelectActivity (IntPtr javaReference, JniHandleOwnership transfer)
|
||||||
: base(javaReference, transfer)
|
: base(javaReference, transfer)
|
||||||
{
|
{
|
||||||
@@ -136,7 +136,9 @@ namespace keepass2android
|
|||||||
EventHandler createNewButtonClick = (sender, e) =>
|
EventHandler createNewButtonClick = (sender, e) =>
|
||||||
{
|
{
|
||||||
//ShowFilenameDialog(false, true, true, Android.OS.Environment.ExternalStorageDirectory + GetString(Resource.String.default_file_path), "", Intents.RequestCodeFileBrowseForCreate)
|
//ShowFilenameDialog(false, true, true, Android.OS.Environment.ExternalStorageDirectory + GetString(Resource.String.default_file_path), "", Intents.RequestCodeFileBrowseForCreate)
|
||||||
StartActivityForResult(typeof (CreateDatabaseActivity), 0);
|
Intent i = new Intent(this, typeof (CreateDatabaseActivity));
|
||||||
|
this.AppTask.ToIntent(i);
|
||||||
|
StartActivityForResult(i, 0);
|
||||||
};
|
};
|
||||||
createNewButton.Click += createNewButtonClick;
|
createNewButton.Click += createNewButtonClick;
|
||||||
|
|
||||||
@@ -193,11 +195,11 @@ namespace keepass2android
|
|||||||
|
|
||||||
class MyViewBinder: Java.Lang.Object, SimpleCursorAdapter.IViewBinder
|
class MyViewBinder: Java.Lang.Object, SimpleCursorAdapter.IViewBinder
|
||||||
{
|
{
|
||||||
private Kp2aApp app;
|
private readonly Kp2aApp _app;
|
||||||
|
|
||||||
public MyViewBinder(Kp2aApp app)
|
public MyViewBinder(Kp2aApp app)
|
||||||
{
|
{
|
||||||
this.app = app;
|
_app = app;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SetViewValue(View view, ICursor cursor, int columnIndex)
|
public bool SetViewValue(View view, ICursor cursor, int columnIndex)
|
||||||
@@ -207,7 +209,7 @@ namespace keepass2android
|
|||||||
String path = cursor.GetString(columnIndex);
|
String path = cursor.GetString(columnIndex);
|
||||||
TextView textView = (TextView)view;
|
TextView textView = (TextView)view;
|
||||||
IOConnectionInfo ioc = new IOConnectionInfo {Path = path};
|
IOConnectionInfo ioc = new IOConnectionInfo {Path = path};
|
||||||
textView.Text = app.GetFileStorage(ioc).GetDisplayName(ioc);
|
textView.Text = _app.GetFileStorage(ioc).GetDisplayName(ioc);
|
||||||
textView.Tag = ioc.Path;
|
textView.Tag = ioc.Path;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -421,9 +423,7 @@ namespace keepass2android
|
|||||||
if (ShowRecentFiles() != _recentMode)
|
if (ShowRecentFiles() != _recentMode)
|
||||||
{
|
{
|
||||||
// Restart the activity
|
// Restart the activity
|
||||||
Intent intent = Intent;
|
Recreate();
|
||||||
StartActivity(intent);
|
|
||||||
Finish();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -966,4 +966,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AndroidResource Include="Resources\drawable\ic_menu_copy_holo_light.png" />
|
<AndroidResource Include="Resources\drawable\ic_menu_copy_holo_light.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\xml\searchable_debug.xml" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -36,9 +36,12 @@ namespace keepass2android
|
|||||||
return ((CheckBox)FindViewById(resId)).Checked;
|
return ((CheckBox)FindViewById(resId)).Checked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AppTask _appTask;
|
||||||
|
|
||||||
protected override void OnCreate(Bundle bundle)
|
protected override void OnCreate(Bundle bundle)
|
||||||
{
|
{
|
||||||
base.OnCreate(bundle);
|
base.OnCreate(bundle);
|
||||||
|
_appTask = AppTask.GetTaskInOnCreate(bundle, Intent);
|
||||||
SetContentView(Resource.Layout.search);
|
SetContentView(Resource.Layout.search);
|
||||||
SearchParameters sp = new SearchParameters();
|
SearchParameters sp = new SearchParameters();
|
||||||
PopulateCheckBox(Resource.Id.cbSearchInTitle, sp.SearchInTitles);
|
PopulateCheckBox(Resource.Id.cbSearchInTitle, sp.SearchInTitles);
|
||||||
@@ -92,8 +95,11 @@ namespace keepass2android
|
|||||||
searchIntent.PutExtra("CaseSensitive", GetCheckBoxValue(Resource.Id.cbCaseSensitive));
|
searchIntent.PutExtra("CaseSensitive", GetCheckBoxValue(Resource.Id.cbCaseSensitive));
|
||||||
searchIntent.PutExtra("ExcludeExpired", GetCheckBoxValue(Resource.Id.cbExcludeExpiredEntries));
|
searchIntent.PutExtra("ExcludeExpired", GetCheckBoxValue(Resource.Id.cbExcludeExpiredEntries));
|
||||||
searchIntent.PutExtra(SearchManager.Query, searchString);
|
searchIntent.PutExtra(SearchManager.Query, searchString);
|
||||||
StartActivityForResult(searchIntent, 0);
|
//forward appTask:
|
||||||
Finish();
|
_appTask.ToIntent(searchIntent);
|
||||||
|
|
||||||
|
Util.FinishAndForward(this, searchIntent);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user