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:
Philipp Crocoll
2014-05-14 07:23:31 +02:00
parent 00332523e6
commit f613206dab
19 changed files with 246 additions and 89 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -323,6 +323,12 @@ namespace keepass2android
} }
public static void FinishAndForward(Activity activity, Intent i)
{
i.SetFlags(ActivityFlags.ForwardResult);
activity.StartActivity(i);
activity.Finish();
}
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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