diff --git a/src/Kp2aBusinessLogic/database/PwEntryOutput.cs b/src/Kp2aBusinessLogic/database/PwEntryOutput.cs
new file mode 100644
index 00000000..8ab57d0b
--- /dev/null
+++ b/src/Kp2aBusinessLogic/database/PwEntryOutput.cs
@@ -0,0 +1,60 @@
+using System;
+using KeePass.Util.Spr;
+using KeePassLib;
+using KeePassLib.Collections;
+using KeePassLib.Security;
+
+namespace keepass2android
+{
+ ///
+ /// Represents the strings which are output from a PwEntry.
+ ///
+ /// In contrast to the original PwEntry, this means that placeholders are replaced. Also, plugins may modify
+ /// or add fields.
+ public class PwEntryOutput
+ {
+ private readonly PwEntry _entry;
+ private readonly PwDatabase _db;
+ private readonly ProtectedStringDictionary _outputStrings = new ProtectedStringDictionary();
+
+ ///
+ /// Constructs the PwEntryOutput by replacing the placeholders
+ ///
+ public PwEntryOutput(PwEntry entry, PwDatabase db)
+ {
+ _entry = entry;
+ _db = db;
+
+ foreach (var pair in entry.Strings)
+ {
+ _outputStrings.Set(pair.Key, new ProtectedString(entry.Strings.Get(pair.Key).IsProtected, GetStringAndReplacePlaceholders(pair.Key)));
+ }
+ }
+
+ string GetStringAndReplacePlaceholders(string key)
+ {
+ String value = Entry.Strings.ReadSafe(key);
+ value = SprEngine.Compile(value, new SprContext(Entry, _db, SprCompileFlags.All));
+ return value;
+ }
+
+
+ ///
+ /// Returns the ID of the entry
+ ///
+ public PwUuid Uuid
+ {
+ get { return Entry.Uuid; }
+ }
+
+ ///
+ /// The output strings for the represented entry
+ ///
+ public ProtectedStringDictionary OutputStrings { get { return _outputStrings; } }
+
+ public PwEntry Entry
+ {
+ get { return _entry; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Kp2aUnitTests/TestIntentsAndBundles.cs b/src/Kp2aUnitTests/TestIntentsAndBundles.cs
new file mode 100644
index 00000000..64f4f766
--- /dev/null
+++ b/src/Kp2aUnitTests/TestIntentsAndBundles.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Android.App;
+using Android.Content;
+using Android.OS;
+using Java.IO;
+using KeePassLib;
+using KeePassLib.Interfaces;
+using KeePassLib.Keys;
+using KeePassLib.Serialization;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using keepass2android;
+
+namespace Kp2aUnitTests
+{
+ [TestClass]
+ internal class TestIntentsAndBundles
+ {
+ [TestMethod]
+ public void StringArray()
+ {
+ string[] dataIn = new string[] { "a","bcd"};
+ Intent i= new Intent();
+ i.PutExtra("key", dataIn);
+
+ Bundle extras = i.Extras;
+ var dataOut = extras.GetStringArray("key");
+ Assert.AreEqual(dataIn.Length, dataOut.Length);
+ Assert.AreEqual(dataIn[0], dataOut[0]);
+ Assert.AreEqual(dataIn[1], dataOut[1]);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/keepass2android/ChangeLog.cs b/src/keepass2android/ChangeLog.cs
index fd5973b6..c1dd359b 100644
--- a/src/keepass2android/ChangeLog.cs
+++ b/src/keepass2android/ChangeLog.cs
@@ -38,7 +38,7 @@ namespace keepass2android
ctx.GetString(Resource.String.ChangeLog)
};
- builder.SetPositiveButton(Android.Resource.String.Ok, (dlgSender, dlgEvt) => { });
+ builder.SetPositiveButton(Android.Resource.String.Ok, (dlgSender, dlgEvt) => {((AlertDialog)dlgSender).Dismiss(); });
builder.SetCancelable(false);
builder.SetMessage("temp");
diff --git a/src/keepass2android/EntryActivity.cs b/src/keepass2android/EntryActivity.cs
index bb16b1de..60f7fb85 100644
--- a/src/keepass2android/EntryActivity.cs
+++ b/src/keepass2android/EntryActivity.cs
@@ -52,17 +52,21 @@ namespace keepass2android
public const String KeyRefreshPos = "refresh_pos";
public const String KeyCloseAfterCreate = "close_after_create";
- public static void Launch(Activity act, PwEntry pw, int pos, AppTask appTask)
+ public static void Launch(Activity act, PwEntry pw, int pos, AppTask appTask, ActivityFlags? flags = null)
{
Intent i = new Intent(act, typeof(EntryActivity));
-
i.PutExtra(KeyEntry, pw.Uuid.ToHexString());
i.PutExtra(KeyRefreshPos, pos);
- appTask.ToIntent(i);
+ if (flags != null)
+ i.SetFlags((ActivityFlags) flags);
- act.StartActivityForResult(i, 0);
+ appTask.ToIntent(i);
+ if (flags != null && (((ActivityFlags) flags) | ActivityFlags.ForwardResult) == ActivityFlags.ForwardResult)
+ act.StartActivity(i);
+ else
+ act.StartActivityForResult(i, 0);
}
public EntryActivity (IntPtr javaReference, JniHandleOwnership transfer)
@@ -93,6 +97,9 @@ namespace keepass2android
private readonly Dictionary _stringViews = new Dictionary();
private readonly List _pendingMenuOptions = new List();
+ //make sure _timer doesn't go out of scope:
+ private Timer _timer;
+
protected void SetEntryView()
{
@@ -298,6 +305,7 @@ namespace keepass2android
!prefs.GetBoolean(GetString(Resource.String.maskpass_key), Resources.GetBoolean(Resource.Boolean.maskpass_default));
base.OnCreate(savedInstanceState);
+ RequestWindowFeature(WindowFeatures.IndeterminateProgress);
new ActivityDesign(this).ApplyTheme();
@@ -342,15 +350,15 @@ namespace keepass2android
SetupEditButtons();
- //depending on the app task, the final things to do might be delayed, so let the appTask call CompleteOnCreate when appropriate
- _appTask.OnCompleteCreateEntryActivity(this);
-
App.Kp2a.GetDb().LastOpenedEntry = new PwEntryOutput(Entry, App.Kp2a.GetDb().KpDatabase);
RegisterReceiver(new PluginActionReceiver(this), new IntentFilter(Strings.ActionAddEntryAction));
RegisterReceiver(new PluginFieldReceiver(this), new IntentFilter(Strings.ActionSetEntryField));
new Thread(NotifyPluginsOnOpen).Start();
+
+ //the rest of the things to do depends on the current app task:
+ _appTask.CompleteOnCreateEntryActivity(this);
}
private void NotifyPluginsOnOpen()
@@ -381,29 +389,17 @@ namespace keepass2android
}
}
- public void CompleteOnCreate()
- {
+
- Intent showNotIntent = new Intent(this, typeof(CopyToClipboardService));
+ internal void StartNotificationsService(bool closeAfterCreate)
+ {
+ Intent showNotIntent = new Intent(this, typeof (CopyToClipboardService));
showNotIntent.SetAction(Intents.ShowNotification);
showNotIntent.PutExtra(KeyEntry, Entry.Uuid.ToHexString());
- bool closeAfterCreate = _appTask.CloseEntryActivityAfterCreate;
+
showNotIntent.PutExtra(KeyCloseAfterCreate, closeAfterCreate);
StartService(showNotIntent);
-
- Kp2aLog.Log("Requesting copy to clipboard for Uuid=" + Entry.Uuid.ToHexString());
-
- /*foreach (PwUuid key in App.Kp2a.GetDb().entries.Keys)
- {
- Kp2aLog.Log(this,key.ToHexString() + " -> " + App.Kp2a.GetDb().entries[key].Uuid.ToHexString());
- }*/
-
- if (closeAfterCreate)
- {
- SetResult(KeePass.ExitCloseAfterTaskComplete);
- Finish();
- }
}
@@ -805,12 +801,24 @@ namespace keepass2android
{
Intent ret = new Intent();
ret.PutExtra(KeyRefreshPos, _pos);
-
+ _appTask.ToIntent(ret);
SetResult(KeePass.ExitRefresh, ret);
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) {
base.OnActivityResult(requestCode, resultCode, data);
+ if (AppTask.TryGetFromActivityResult(data, ref _appTask))
+ {
+ //make sure app task is passed to calling activity.
+ //the result code might be modified later.
+ Intent retData = new Intent();
+ _appTask.ToIntent(retData);
+ SetResult(KeePass.ExitNormal, retData);
+ }
+
+
+
+
if ( resultCode == KeePass.ExitRefresh || resultCode == KeePass.ExitRefreshTitle ) {
if ( resultCode == KeePass.ExitRefreshTitle ) {
RequiresRefresh ();
@@ -1019,33 +1027,8 @@ namespace keepass2android
}
- ///
- /// brings up a dialog asking the user whether he wants to add the given URL to the entry for automatic finding
- ///
- public void AskAddUrlThenCompleteCreate(string url)
- {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.SetTitle(GetString(Resource.String.AddUrlToEntryDialog_title));
-
- builder.SetMessage(GetString(Resource.String.AddUrlToEntryDialog_text, new Java.Lang.Object[] {url}));
-
- builder.SetPositiveButton(GetString(Resource.String.yes), (dlgSender, dlgEvt) =>
- {
-
- AddUrlToEntryThenCompleteCreate(url);
-
- });
-
- builder.SetNegativeButton(GetString(Resource.String.no), (dlgSender, dlgEvt) =>
- {
- CompleteOnCreate();
- });
-
- Dialog dialog = builder.Create();
- dialog.Show();
-
- }
- private void AddUrlToEntryThenCompleteCreate(string url)
+
+ internal void AddUrlToEntry(string url, Action finishAction)
{
PwEntry initialEntry = Entry.CloneDeep();
@@ -1076,7 +1059,7 @@ namespace keepass2android
ActionOnFinish closeOrShowError = new ActionOnFinish((success, message) =>
{
OnFinish.DisplayMessage(this, message);
- CompleteOnCreate();
+ finishAction();
});
@@ -1085,7 +1068,7 @@ namespace keepass2android
ProgressTask pt = new ProgressTask(App.Kp2a, this, runnable);
pt.Run();
- }
+ }
public void ToggleVisibility()
{
_showPassword = !_showPassword;
@@ -1120,5 +1103,27 @@ namespace keepass2android
{
PluginHost.AddEntryToIntent(intent, App.Kp2a.GetDb().LastOpenedEntry);
}
+
+ public void CloseAfterTaskComplete()
+ {
+ //before closing, wait a little to get plugin updates
+ int numPlugins = new PluginDatabase(this).GetPluginsWithAcceptedScope(Strings.ScopeCurrentEntry).Count();
+ var timeToWait = TimeSpan.FromMilliseconds(500*numPlugins);
+ SetProgressBarIndeterminateVisibility(true);
+ _timer = new Timer(obj =>
+ {
+ RunOnUiThread(() =>
+ {
+ //task is completed -> return NullTask
+ Intent resIntent = new Intent();
+ new NullTask().ToIntent(resIntent);
+ SetResult(KeePass.ExitCloseAfterTaskComplete, resIntent);
+ //close activity:
+ Finish();
+ }
+ );
+ },
+ null, timeToWait, TimeSpan.FromMilliseconds(-1));
+ }
}
}
\ No newline at end of file
diff --git a/src/keepass2android/EntryActivityClasses/CopyToClipboardPopupMenuIcon.cs b/src/keepass2android/EntryActivityClasses/CopyToClipboardPopupMenuIcon.cs
new file mode 100644
index 00000000..a1a4207d
--- /dev/null
+++ b/src/keepass2android/EntryActivityClasses/CopyToClipboardPopupMenuIcon.cs
@@ -0,0 +1,41 @@
+using Android.Content;
+using Android.Graphics.Drawables;
+using PluginHostTest;
+
+namespace keepass2android
+{
+ ///
+ /// Reperesents the popup menu item in EntryActivity to copy a string to clipboard
+ ///
+ class CopyToClipboardPopupMenuIcon : IPopupMenuItem
+ {
+ private readonly Context _context;
+ private readonly IStringView _stringView;
+
+ public CopyToClipboardPopupMenuIcon(Context context, IStringView stringView)
+ {
+ _context = context;
+ _stringView = stringView;
+
+ }
+
+ public Drawable Icon
+ {
+ get
+ {
+ return _context.Resources.GetDrawable(Resource.Drawable.ic_menu_copy_holo_light);
+ }
+ }
+ public string Text
+ {
+ //TODO localize
+ get { return "Copy to clipboard"; }
+ }
+
+
+ public void HandleClick()
+ {
+ CopyToClipboardService.CopyValueToClipboardWithTimeout(_context, _stringView.Text);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/keepass2android/EntryActivityClasses/ExtraStringView.cs b/src/keepass2android/EntryActivityClasses/ExtraStringView.cs
new file mode 100644
index 00000000..65edfb48
--- /dev/null
+++ b/src/keepass2android/EntryActivityClasses/ExtraStringView.cs
@@ -0,0 +1,44 @@
+using System;
+using Android.Views;
+using Android.Widget;
+
+namespace keepass2android
+{
+ internal class ExtraStringView : IStringView
+ {
+ private readonly View _container;
+ private readonly TextView _valueView;
+ private readonly TextView _keyView;
+
+ public ExtraStringView(LinearLayout container, TextView valueView, TextView keyView)
+ {
+ _container = container;
+ _valueView = valueView;
+ _keyView = keyView;
+ }
+
+ public View View
+ {
+ get { return _container; }
+ }
+
+ public string Text
+ {
+ get { return _valueView.Text; }
+ set
+ {
+ if (String.IsNullOrEmpty(value))
+ {
+ _valueView.Visibility = ViewStates.Gone;
+ _keyView.Visibility = ViewStates.Gone;
+ }
+ else
+ {
+ _valueView.Visibility = ViewStates.Visible;
+ _keyView.Visibility = ViewStates.Visible;
+ _valueView.Text = value;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/keepass2android/EntryActivityClasses/GotoUrlMenuItem.cs b/src/keepass2android/EntryActivityClasses/GotoUrlMenuItem.cs
new file mode 100644
index 00000000..b1a56d97
--- /dev/null
+++ b/src/keepass2android/EntryActivityClasses/GotoUrlMenuItem.cs
@@ -0,0 +1,33 @@
+using Android.Graphics.Drawables;
+using PluginHostTest;
+
+namespace keepass2android
+{
+ ///
+ /// Reperesents the popup menu item in EntryActivity to go to the URL in the field
+ ///
+ class GotoUrlMenuItem : IPopupMenuItem
+ {
+ private readonly EntryActivity _ctx;
+
+ public GotoUrlMenuItem(EntryActivity ctx)
+ {
+ _ctx = ctx;
+ }
+
+ public Drawable Icon
+ {
+ get { return _ctx.Resources.GetDrawable(Android.Resource.Drawable.IcMenuUpload); }
+ }
+
+ public string Text
+ {
+ get { return _ctx.Resources.GetString(Resource.String.menu_url); }
+ }
+
+ public void HandleClick()
+ {
+ _ctx.GotoUrl();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/keepass2android/EntryActivityClasses/IPopupMenuItem.cs b/src/keepass2android/EntryActivityClasses/IPopupMenuItem.cs
new file mode 100644
index 00000000..9cb8c149
--- /dev/null
+++ b/src/keepass2android/EntryActivityClasses/IPopupMenuItem.cs
@@ -0,0 +1,17 @@
+using System;
+using Android.Graphics.Drawables;
+using KeePassLib;
+
+namespace keepass2android
+{
+ ///
+ /// Interface for popup menu items in EntryActivity
+ ///
+ internal interface IPopupMenuItem
+ {
+ Drawable Icon { get; }
+ String Text { get; }
+
+ void HandleClick();
+ }
+}
\ No newline at end of file
diff --git a/src/keepass2android/EntryActivityClasses/IStringView.cs b/src/keepass2android/EntryActivityClasses/IStringView.cs
new file mode 100644
index 00000000..a5c5036c
--- /dev/null
+++ b/src/keepass2android/EntryActivityClasses/IStringView.cs
@@ -0,0 +1,7 @@
+namespace keepass2android
+{
+ internal interface IStringView
+ {
+ string Text { set; get; }
+ }
+}
\ No newline at end of file
diff --git a/src/keepass2android/EntryActivityClasses/OpenBinaryPopupItem.cs b/src/keepass2android/EntryActivityClasses/OpenBinaryPopupItem.cs
new file mode 100644
index 00000000..38c07867
--- /dev/null
+++ b/src/keepass2android/EntryActivityClasses/OpenBinaryPopupItem.cs
@@ -0,0 +1,40 @@
+using Android.Graphics.Drawables;
+using PluginHostTest;
+
+namespace keepass2android
+{
+ ///
+ /// Represents the popup menu item in EntryActivity to open the associated attachment
+ ///
+ internal class OpenBinaryPopupItem : IPopupMenuItem
+ {
+ private readonly string _key;
+ private readonly EntryActivity _entryActivity;
+
+ public OpenBinaryPopupItem(string key, EntryActivity entryActivity)
+ {
+ _key = key;
+ _entryActivity = entryActivity;
+ }
+
+ public Drawable Icon
+ {
+ get { return _entryActivity.Resources.GetDrawable(Android.Resource.Drawable.IcMenuShare); }
+ }
+
+ public string Text
+ {
+ get { return _entryActivity.Resources.GetString(Resource.String.SaveAttachmentDialog_open); }
+ }
+
+ public void HandleClick()
+ {
+ Android.Net.Uri newUri = _entryActivity.WriteBinaryToFile(_key, true);
+ if (newUri != null)
+ {
+ _entryActivity.OpenBinaryFile(newUri);
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/keepass2android/EntryActivityClasses/PluginMenuOption.cs b/src/keepass2android/EntryActivityClasses/PluginMenuOption.cs
new file mode 100644
index 00000000..d3e91ef4
--- /dev/null
+++ b/src/keepass2android/EntryActivityClasses/PluginMenuOption.cs
@@ -0,0 +1,14 @@
+using Android.Content;
+using Android.Graphics.Drawables;
+
+namespace keepass2android
+{
+ class PluginMenuOption
+ {
+ public string DisplayText { get; set; }
+
+ public Drawable Icon { get; set; }
+
+ public Intent Intent { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/keepass2android/EntryActivityClasses/PluginPopupMenuItem.cs b/src/keepass2android/EntryActivityClasses/PluginPopupMenuItem.cs
new file mode 100644
index 00000000..779f02ad
--- /dev/null
+++ b/src/keepass2android/EntryActivityClasses/PluginPopupMenuItem.cs
@@ -0,0 +1,59 @@
+using Android.Content;
+using Android.Graphics.Drawables;
+using Android.OS;
+using Keepass2android.Pluginsdk;
+
+namespace keepass2android
+{
+ ///
+ /// Represents a popup menu item in EntryActivity which was added by a plugin. The click will therefore broadcast to the plugin.
+ ///
+ class PluginPopupMenuItem : IPopupMenuItem
+ {
+ private readonly EntryActivity _activity;
+ private readonly string _pluginPackage;
+ private readonly string _fieldId;
+ private readonly string _popupItemId;
+ private readonly string _displayText;
+ private readonly int _iconId;
+ private readonly Bundle _bundleExtra;
+
+ public PluginPopupMenuItem(EntryActivity activity, string pluginPackage, string fieldId, string popupItemId, string displayText, int iconId, Bundle bundleExtra)
+ {
+ _activity = activity;
+ _pluginPackage = pluginPackage;
+ _fieldId = fieldId;
+ _popupItemId = popupItemId;
+ _displayText = displayText;
+ _iconId = iconId;
+ _bundleExtra = bundleExtra;
+ }
+
+ public Drawable Icon
+ {
+ get { return _activity.PackageManager.GetResourcesForApplication(_pluginPackage).GetDrawable(_iconId); }
+ }
+ public string Text
+ {
+ get { return _displayText; }
+ }
+
+ public string PopupItemId
+ {
+ get { return _popupItemId; }
+ }
+
+ public void HandleClick()
+ {
+ Intent i = new Intent(Strings.ActionEntryActionSelected);
+ i.SetPackage(_pluginPackage);
+ i.PutExtra(Strings.ExtraActionData, _bundleExtra);
+ i.PutExtra(Strings.ExtraFieldId, _fieldId);
+ i.PutExtra(Strings.ExtraSender, _activity.PackageName);
+
+ _activity.AddEntryToIntent(i);
+
+ _activity.SendBroadcast(i);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/keepass2android/EntryActivityClasses/StandardStringView.cs b/src/keepass2android/EntryActivityClasses/StandardStringView.cs
new file mode 100644
index 00000000..bcbcb019
--- /dev/null
+++ b/src/keepass2android/EntryActivityClasses/StandardStringView.cs
@@ -0,0 +1,44 @@
+using System;
+using Android.App;
+using Android.Views;
+using Android.Widget;
+
+namespace keepass2android
+{
+ internal class StandardStringView : IStringView
+ {
+ private readonly int _viewId;
+ private readonly int _containerViewId;
+ private readonly Activity _activity;
+
+ public StandardStringView(int viewId, int containerViewId, Activity activity)
+ {
+ _viewId = viewId;
+ _containerViewId = containerViewId;
+ _activity = activity;
+ }
+
+ public string Text
+ {
+ set
+ {
+ View container = _activity.FindViewById(_containerViewId);
+ TextView tv = (TextView) _activity.FindViewById(_viewId);
+ if (String.IsNullOrEmpty(value))
+ {
+ container.Visibility = tv.Visibility = ViewStates.Gone;
+ }
+ else
+ {
+ container.Visibility = tv.Visibility = ViewStates.Visible;
+ tv.Text = value;
+ }
+ }
+ get
+ {
+ TextView tv = (TextView) _activity.FindViewById(_viewId);
+ return tv.Text;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/keepass2android/EntryActivityClasses/ToggleVisibilityPopupMenuItem.cs b/src/keepass2android/EntryActivityClasses/ToggleVisibilityPopupMenuItem.cs
new file mode 100644
index 00000000..54ff1890
--- /dev/null
+++ b/src/keepass2android/EntryActivityClasses/ToggleVisibilityPopupMenuItem.cs
@@ -0,0 +1,46 @@
+using Android.Graphics.Drawables;
+using PluginHostTest;
+
+namespace keepass2android
+{
+ ///
+ /// Reperesents the popup menu item in EntryActivity to toggle visibility of all protected strings (e.g. Password)
+ ///
+ class ToggleVisibilityPopupMenuItem : IPopupMenuItem
+ {
+ private readonly EntryActivity _activity;
+
+
+ public ToggleVisibilityPopupMenuItem(EntryActivity activity)
+ {
+ _activity = activity;
+
+ }
+
+ public Drawable Icon
+ {
+ get
+ {
+ //return new TextDrawable("\uF06E", _activity);
+ return _activity.Resources.GetDrawable(Resource.Drawable.ic_action_eye_open);
+
+ }
+ }
+ public string Text
+ {
+ get
+ {
+ return _activity.Resources.GetString(
+ _activity._showPassword ?
+ Resource.String.menu_hide_password
+ : Resource.String.show_password);
+ }
+ }
+
+
+ public void HandleClick()
+ {
+ _activity.ToggleVisibility();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/keepass2android/EntryActivityClasses/WriteBinaryToFilePopupItem.cs b/src/keepass2android/EntryActivityClasses/WriteBinaryToFilePopupItem.cs
new file mode 100644
index 00000000..a90fc61b
--- /dev/null
+++ b/src/keepass2android/EntryActivityClasses/WriteBinaryToFilePopupItem.cs
@@ -0,0 +1,35 @@
+using Android.Graphics.Drawables;
+using PluginHostTest;
+
+namespace keepass2android
+{
+ ///
+ /// Represents the popup menu item in EntryActivity to store the binary attachment on SD card
+ ///
+ internal class WriteBinaryToFilePopupItem : IPopupMenuItem
+ {
+ private readonly string _key;
+ private readonly EntryActivity _activity;
+
+ public WriteBinaryToFilePopupItem(string key, EntryActivity activity)
+ {
+ _key = key;
+ _activity = activity;
+ }
+
+ public Drawable Icon
+ {
+ get { return _activity.Resources.GetDrawable(Android.Resource.Drawable.IcMenuSave); }
+ }
+
+ public string Text
+ {
+ get { return _activity.Resources.GetString(Resource.String.SaveAttachmentDialog_save); }
+ }
+
+ public void HandleClick()
+ {
+ _activity.WriteBinaryToFile(_key, false);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/keepass2android/EntryEditActivity.cs b/src/keepass2android/EntryEditActivity.cs
index 7f6f0a4b..2b747a93 100644
--- a/src/keepass2android/EntryEditActivity.cs
+++ b/src/keepass2android/EntryEditActivity.cs
@@ -601,7 +601,7 @@ namespace keepass2android
Intent intent = Intent;
intent.PutExtra(IntentContinueWithEditing, true);
OverridePendingTransition(0, 0);
- intent.AddFlags(ActivityFlags.NoAnimation);
+ intent.AddFlags(ActivityFlags.NoAnimation | ActivityFlags.ForwardResult);
_closeForReload = true;
SetResult(KeePass.ExitRefreshTitle); //probably the entry will be modified -> let the EditActivity refresh to be safe
Finish();
diff --git a/src/keepass2android/GroupBaseActivity.cs b/src/keepass2android/GroupBaseActivity.cs
index 6e514659..4949dd65 100644
--- a/src/keepass2android/GroupBaseActivity.cs
+++ b/src/keepass2android/GroupBaseActivity.cs
@@ -70,7 +70,11 @@ namespace keepass2android
{
base.OnActivityResult(requestCode, resultCode, data);
- AppTask.TryGetFromActivityResult(data, ref AppTask);
+ if (AppTask.TryGetFromActivityResult(data, ref AppTask))
+ {
+ //make sure the app task is passed to the calling activity
+ AppTask.SetActivityResult(this, KeePass.ExitNormal);
+ }
if (resultCode == Result.Ok)
{
@@ -236,17 +240,24 @@ namespace keepass2android
class SuggestionListener: Java.Lang.Object, SearchView.IOnSuggestionListener
{
private readonly CursorAdapter _suggestionsAdapter;
+ private readonly GroupBaseActivity _activity;
+ private readonly IMenuItem _searchItem;
- public SuggestionListener(CursorAdapter suggestionsAdapter)
+
+ public SuggestionListener(CursorAdapter suggestionsAdapter, GroupBaseActivity activity, IMenuItem searchItem)
{
_suggestionsAdapter = suggestionsAdapter;
+ _activity = activity;
+ _searchItem = searchItem;
}
public bool OnSuggestionClick(int position)
{
var cursor = _suggestionsAdapter.Cursor;
cursor.MoveToPosition(position);
- var x = cursor.GetString(cursor.GetColumnIndexOrThrow(SearchManager.SuggestColumnIntentDataId));
+ string entryIdAsHexString = cursor.GetString(cursor.GetColumnIndexOrThrow(SearchManager.SuggestColumnIntentDataId));
+ EntryActivity.Launch(_activity, App.Kp2a.GetDb().Entries[new PwUuid(MemUtil.HexStringToByteArray(entryIdAsHexString))],-1,_activity.AppTask);
+ ((SearchView) _searchItem.ActionView).Iconified = true;
return true;
}
@@ -255,6 +266,37 @@ namespace keepass2android
return false;
}
}
+
+ class OnQueryTextListener: Java.Lang.Object, SearchView.IOnQueryTextListener
+ {
+ private readonly GroupBaseActivity _activity;
+
+ public OnQueryTextListener(GroupBaseActivity activity)
+ {
+ _activity = activity;
+ }
+
+ public bool OnQueryTextChange(string newText)
+ {
+ return false;
+ }
+
+ public bool OnQueryTextSubmit(string query)
+ {
+ if (String.IsNullOrEmpty(query))
+ return false; //let the default happen
+
+ Intent searchIntent = new Intent(_activity, typeof(search.SearchResults));
+ searchIntent.SetAction(Intent.ActionSearch); //currently not necessary to set because SearchResults doesn't care, but let's be as close to the default as possible
+ searchIntent.PutExtra(SearchManager.Query, query);
+ //forward appTask:
+ _activity.AppTask.ToIntent(searchIntent);
+
+ _activity.StartActivityForResult(searchIntent, 0);
+
+ return true;
+ }
+ }
public override bool OnCreateOptionsMenu(IMenu menu) {
base.OnCreateOptionsMenu(menu);
@@ -263,11 +305,13 @@ namespace keepass2android
inflater.Inflate(Resource.Menu.group, menu);
if (Util.HasActionBar(this))
{
- var searchManager = (SearchManager) GetSystemService(Context.SearchService);
- var searchView = (SearchView) menu.FindItem(Resource.Id.menu_search).ActionView;
+ var searchManager = (SearchManager) GetSystemService(SearchService);
+ IMenuItem searchItem = menu.FindItem(Resource.Id.menu_search);
+ var searchView = (SearchView) searchItem.ActionView;
searchView.SetSearchableInfo(searchManager.GetSearchableInfo(ComponentName));
- searchView.SetOnSuggestionListener(new SuggestionListener(searchView.SuggestionsAdapter));
+ searchView.SetOnSuggestionListener(new SuggestionListener(searchView.SuggestionsAdapter, this, searchItem));
+ searchView.SetOnQueryTextListener(new OnQueryTextListener(this));
}
var item = menu.FindItem(Resource.Id.menu_sync);
if (item != null)
diff --git a/src/keepass2android/KeePass.cs b/src/keepass2android/KeePass.cs
index dab2d040..ec22af59 100644
--- a/src/keepass2android/KeePass.cs
+++ b/src/keepass2android/KeePass.cs
@@ -46,6 +46,7 @@ using String = System.String;
* (AdvancedSearch Menu) -> Search -> SearchResults -> EntryView -> EntryEdit
* (SearchWidget) -> SearchResults -> EntryView -> EntryEdit
* Password -> ShareUrlResults -> EntryView
+ * FileSelect -> Group (after Create DB)
*
*
* In each of these activities, an AppTask may be present and must be passed to started activities and ActivityResults
@@ -84,11 +85,23 @@ namespace keepass2android
AppTask _appTask;
private ActivityDesign _design;
- protected override void OnCreate (Bundle bundle)
+ protected override void OnCreate(Bundle savedInstanceState)
{
- base.OnCreate (bundle);
+ base.OnCreate(savedInstanceState);
_design.ApplyTheme();
- _appTask = AppTask.GetTaskInOnCreate(bundle, Intent);
+ //see comment to this in PasswordActivity.
+ //Note that this activity is affected even though it's finished when the app is closed because it
+ //seems that the "app launch intent" is re-delivered, so this might end up here.
+ if ((_appTask == null) && (Intent.Flags.HasFlag(ActivityFlags.LaunchedFromHistory)))
+ {
+ _appTask = new NullTask();
+ }
+ else
+ {
+ _appTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
+ }
+
+
Kp2aLog.Log("KeePass.OnCreate");
}
@@ -274,9 +287,8 @@ namespace keepass2android
Intent intent = new Intent(this, typeof(FileSelectActivity));
_appTask.ToIntent(intent);
-
-
- StartActivityForResult(intent, 0);
+ intent.AddFlags(ActivityFlags.ForwardResult);
+ StartActivity(intent);
Finish();
}
@@ -288,11 +300,6 @@ namespace keepass2android
}
- protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) {
- base.OnActivityResult(requestCode, resultCode, data);
-
- Finish();
- }
}
}
diff --git a/src/keepass2android/PasswordActivity.cs b/src/keepass2android/PasswordActivity.cs
index 87d89f82..27806ecc 100644
--- a/src/keepass2android/PasswordActivity.cs
+++ b/src/keepass2android/PasswordActivity.cs
@@ -179,11 +179,11 @@ namespace keepass2android
Intent i = new Intent(act, typeof(PasswordActivity));
PutIoConnectionToIntent(ioc, i);
- i.SetFlags(ActivityFlags.ClearTask);
+ i.SetFlags(ActivityFlags.ClearTask | ActivityFlags.ForwardResult);
appTask.ToIntent(i);
- act.StartActivityForResult(i, 0);
+ act.StartActivity(i);
}
@@ -198,11 +198,21 @@ namespace keepass2android
Kp2aLog.Log("PasswordActivity.OnActivityResult "+resultCode+"/"+requestCode);
+ AppTask.TryGetFromActivityResult(data, ref AppTask);
+
//NOTE: original code from k eepassdroid used switch ((Android.App.Result)requestCode) { (but doesn't work here, although k eepassdroid works)
switch(resultCode) {
- case KeePass.ExitNormal: // Returned to this screen using the Back key, treat as locking the database
- App.Kp2a.LockDatabase();
+ case KeePass.ExitNormal: // Returned to this screen using the Back key
+ if (PreferenceManager.GetDefaultSharedPreferences(this)
+ .GetBoolean(GetString(Resource.String.LockWhenNavigateBack_key), false))
+ {
+ App.Kp2a.LockDatabase();
+ }
+ //by leaving the app with the back button, the user probably wants to cancel the task
+ //The activity might be resumed (through Android's recent tasks list), then use a NullTask:
+ AppTask = new NullTask();
+ Finish();
break;
case KeePass.ExitLock:
// The database has already been locked, and the quick unlock screen will be shown if appropriate
@@ -266,6 +276,7 @@ namespace keepass2android
}
+
private void LoadOtpFile()
{
new LoadingDialog