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" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Compile Include="TestIntentsAndBundles.cs" />
 | 
			
		||||
    <Compile Include="ProgressDialogStub.cs" />
 | 
			
		||||
    <Compile Include="TestBase.cs" />
 | 
			
		||||
    <Compile Include="TestCacheSupervisor.cs" />
 | 
			
		||||
@@ -85,6 +86,7 @@
 | 
			
		||||
    <Compile Include="TestSynchronizeCachedDatabase.cs" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <None Include="ClassDiagram1.cd" />
 | 
			
		||||
    <None Include="Resources\AboutResources.txt" />
 | 
			
		||||
    <None Include="Assets\AboutAssets.txt" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,8 @@ namespace Kp2aUnitTests
 | 
			
		||||
        {
 | 
			
		||||
            TestRunner runner = new TestRunner();
 | 
			
		||||
            // 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(typeof(TestLoadDb).GetMethod("LoadErrorWithCertificateTrustFailure"));
 | 
			
		||||
			//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)
 | 
			
		||||
			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);
 | 
			
		||||
			var jsonStr = json.ToString();
 | 
			
		||||
			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());
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -52,6 +52,12 @@ public abstract class PluginActionBroadcastReceiver extends BroadcastReceiver {
 | 
			
		||||
			} 
 | 
			
		||||
			return res;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		protected String[] getProtectedFieldsListFromIntent()
 | 
			
		||||
		{
 | 
			
		||||
			return _intent.getStringArrayExtra(Strings.EXTRA_PROTECTED_FIELDS_LIST);
 | 
			
		||||
		}
 | 
			
		||||
	
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	protected class ActionSelected extends PluginActionBase
 | 
			
		||||
@@ -89,10 +95,23 @@ public abstract class PluginActionBroadcastReceiver extends BroadcastReceiver {
 | 
			
		||||
			return getFieldId() == null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * 
 | 
			
		||||
		 * @return a hashmap containing the entry fields in key/value form
 | 
			
		||||
		 */
 | 
			
		||||
		public HashMap<String, String> getEntryFields() 
 | 
			
		||||
		{
 | 
			
		||||
			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
 | 
			
		||||
@@ -125,6 +144,15 @@ public abstract class PluginActionBroadcastReceiver extends BroadcastReceiver {
 | 
			
		||||
			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
 | 
			
		||||
		{
 | 
			
		||||
			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";
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * 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)
 | 
			
		||||
	 */
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,8 @@ namespace keepass2android
 | 
			
		||||
		private bool _restoringInstanceState;
 | 
			
		||||
		private bool _showPassword;
 | 
			
		||||
 | 
			
		||||
		private ActivityDesign _design;
 | 
			
		||||
		private readonly ActivityDesign _design;
 | 
			
		||||
		private AppTask _appTask;
 | 
			
		||||
 | 
			
		||||
		public CreateDatabaseActivity()
 | 
			
		||||
		{
 | 
			
		||||
@@ -57,7 +58,7 @@ namespace keepass2android
 | 
			
		||||
			_design.ApplyTheme();
 | 
			
		||||
 | 
			
		||||
			SetContentView(Resource.Layout.create_database);
 | 
			
		||||
 | 
			
		||||
			_appTask = AppTask.GetTaskInOnCreate(bundle, Intent);
 | 
			
		||||
 | 
			
		||||
			SetDefaultIoc();
 | 
			
		||||
 | 
			
		||||
@@ -527,7 +528,7 @@ namespace keepass2android
 | 
			
		||||
						dbHelper.CreateFile(_ioc, Filename);
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					GroupActivity.Launch(_activity, new NullTask());
 | 
			
		||||
					GroupActivity.Launch(_activity, _activity._appTask);
 | 
			
		||||
					_activity.Finish();
 | 
			
		||||
 | 
			
		||||
				}
 | 
			
		||||
 
 | 
			
		||||
@@ -127,7 +127,9 @@ namespace keepass2android
 | 
			
		||||
 | 
			
		||||
		public override bool OnSearchRequested()
 | 
			
		||||
		{
 | 
			
		||||
			StartActivityForResult(typeof(SearchActivity), 0);
 | 
			
		||||
			Intent i = new Intent(this, typeof(SearchActivity));
 | 
			
		||||
			AppTask.ToIntent(i);
 | 
			
		||||
			StartActivityForResult(i, 0);
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -214,35 +216,9 @@ namespace keepass2android
 | 
			
		||||
				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;
 | 
			
		||||
				if (clickable)
 | 
			
		||||
					ActionBar.SetDisplayHomeAsUpEnabled(true);
 | 
			
		||||
			}
 | 
			
		||||
			ActionBar.Title = titleText;
 | 
			
		||||
			if (clickable)
 | 
			
		||||
				ActionBar.SetDisplayHomeAsUpEnabled(true);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
@@ -256,6 +232,29 @@ namespace keepass2android
 | 
			
		||||
					ActionBar.SetIcon(drawable);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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) {
 | 
			
		||||
			base.OnCreateOptionsMenu(menu);
 | 
			
		||||
@@ -266,8 +265,9 @@ namespace keepass2android
 | 
			
		||||
			{
 | 
			
		||||
				var searchManager = (SearchManager) GetSystemService(Context.SearchService);
 | 
			
		||||
				var searchView = (SearchView) menu.FindItem(Resource.Id.menu_search).ActionView;
 | 
			
		||||
 | 
			
		||||
				
 | 
			
		||||
				searchView.SetSearchableInfo(searchManager.GetSearchableInfo(ComponentName));
 | 
			
		||||
				searchView.SetOnSuggestionListener(new SuggestionListener(searchView.SuggestionsAdapter));
 | 
			
		||||
			}
 | 
			
		||||
			var item = menu.FindItem(Resource.Id.menu_sync);
 | 
			
		||||
			if (item != null)
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,39 @@ using Java.Lang.Reflect;
 | 
			
		||||
using KeePassLib.Serialization;
 | 
			
		||||
using Exception = System.Exception;
 | 
			
		||||
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
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -115,10 +115,10 @@ namespace keepass2android
 | 
			
		||||
 | 
			
		||||
		private class LockCloseActivityBroadcastReceiver : BroadcastReceiver
 | 
			
		||||
		{			
 | 
			
		||||
			readonly LockCloseActivity _service;
 | 
			
		||||
			public LockCloseActivityBroadcastReceiver(LockCloseActivity service)
 | 
			
		||||
			readonly LockCloseActivity _activity;
 | 
			
		||||
			public LockCloseActivityBroadcastReceiver(LockCloseActivity activity)
 | 
			
		||||
			{
 | 
			
		||||
				_service = service;
 | 
			
		||||
				_activity = activity;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			public override void OnReceive(Context context, Intent intent)
 | 
			
		||||
@@ -126,7 +126,7 @@ namespace keepass2android
 | 
			
		||||
				switch (intent.Action)
 | 
			
		||||
				{
 | 
			
		||||
					case Intents.DatabaseLocked:
 | 
			
		||||
						_service.OnLockDatabase();
 | 
			
		||||
						_activity.OnLockDatabase();
 | 
			
		||||
						break;
 | 
			
		||||
					case Intent.ActionScreenOff:
 | 
			
		||||
						App.Kp2a.OnScreenOff();
 | 
			
		||||
 
 | 
			
		||||
@@ -95,10 +95,10 @@ namespace keepass2android
 | 
			
		||||
 | 
			
		||||
		private class LockCloseListActivityBroadcastReceiver : BroadcastReceiver
 | 
			
		||||
		{
 | 
			
		||||
			readonly LockCloseListActivity _service;
 | 
			
		||||
			public LockCloseListActivityBroadcastReceiver(LockCloseListActivity service)
 | 
			
		||||
			readonly LockCloseListActivity _activity;
 | 
			
		||||
			public LockCloseListActivityBroadcastReceiver(LockCloseListActivity activity)
 | 
			
		||||
			{
 | 
			
		||||
				_service = service;
 | 
			
		||||
				_activity = activity;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			public override void OnReceive(Context context, Intent intent)
 | 
			
		||||
@@ -106,7 +106,7 @@ namespace keepass2android
 | 
			
		||||
				switch (intent.Action)
 | 
			
		||||
				{
 | 
			
		||||
					case Intents.DatabaseLocked:
 | 
			
		||||
						_service.OnLockDatabase();
 | 
			
		||||
						_activity.OnLockDatabase();
 | 
			
		||||
						break;
 | 
			
		||||
					case Intent.ActionScreenOff:
 | 
			
		||||
						App.Kp2a.OnScreenOff();
 | 
			
		||||
 
 | 
			
		||||
@@ -5831,7 +5831,10 @@ namespace keepass2android
 | 
			
		||||
			public const int searchable = 2131034140;
 | 
			
		||||
			
 | 
			
		||||
			// 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()
 | 
			
		||||
			{
 | 
			
		||||
 
 | 
			
		||||
@@ -62,27 +62,12 @@ namespace keepass2android
 | 
			
		||||
			SetResult(KeePass.ExitCloseAfterTaskComplete);
 | 
			
		||||
 | 
			
		||||
			_db = App.Kp2a.GetDb();
 | 
			
		||||
 | 
			
		||||
			String searchUrl = ((SearchUrlTask)AppTask).UrlToSearchFor;
 | 
			
		||||
			
 | 
			
		||||
			if (!_db.Loaded)
 | 
			
		||||
			if (App.Kp2a.DatabaseIsUnlocked)
 | 
			
		||||
			{
 | 
			
		||||
				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);
 | 
			
		||||
				String searchUrl = ((SearchUrlTask)AppTask).UrlToSearchFor;
 | 
			
		||||
				Query(searchUrl);	
 | 
			
		||||
			}
 | 
			
		||||
			// else: LockCloseListActivity.OnResume will trigger a broadcast (LockDatabase) which will cause the activity to be finished.
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -99,8 +84,7 @@ namespace keepass2android
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		private void Query(String url)
 | 
			
		||||
		{
 | 
			
		||||
			
 | 
			
		||||
		{	
 | 
			
		||||
			try
 | 
			
		||||
			{
 | 
			
		||||
				//first: search for exact url
 | 
			
		||||
 
 | 
			
		||||
@@ -322,7 +322,13 @@ namespace keepass2android
 | 
			
		||||
			((Spinner)dialog.FindViewById(Resource.Id.cred_remember_mode)).SetSelection((int)ioc.CredSaveMode);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
 | 
			
		||||
		public static void FinishAndForward(Activity activity, Intent i)
 | 
			
		||||
		{
 | 
			
		||||
			i.SetFlags(ActivityFlags.ForwardResult);
 | 
			
		||||
			activity.StartActivity(i);
 | 
			
		||||
			activity.Finish();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -67,15 +67,17 @@ namespace keepass2android
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		public const int AppNameResource = Resource.String.app_name;
 | 
			
		||||
		public const string AppNameShort = "@string/short_app_name";
 | 
			
		||||
		public const string AppLauncherTitle = "@string/app_name";
 | 
			
		||||
		public const string AppNameShort = "@string/short_app_name" + "DBG";
 | 
			
		||||
		public const string AppLauncherTitle = "@string/app_name" + " Debug";
 | 
			
		||||
#if DEBUG
 | 
			
		||||
		public const string PackagePart = "keepass2android_debug";
 | 
			
		||||
		public const string Searchable = "@xml/searchable_debug";
 | 
			
		||||
#else
 | 
			
		||||
		public const string PackagePart = "keepass2android";
 | 
			
		||||
		public const string Searchable = "@xml/searchable";
 | 
			
		||||
#endif
 | 
			
		||||
		public const int LauncherIcon = Resource.Drawable.ic_launcher;
 | 
			
		||||
		public const string Searchable = "@xml/searchable";
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	/// <summary>
 | 
			
		||||
 
 | 
			
		||||
@@ -48,6 +48,29 @@ namespace keepass2android
 | 
			
		||||
		#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>
 | 
			
		||||
	/// base class for "tasks": these are things the user wants to do and which require several activities
 | 
			
		||||
	/// </summary>
 | 
			
		||||
@@ -271,8 +294,20 @@ namespace keepass2android
 | 
			
		||||
		public override void AfterUnlockDatabase(PasswordActivity act)
 | 
			
		||||
		{
 | 
			
		||||
			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
 | 
			
		||||
@@ -393,30 +428,72 @@ namespace keepass2android
 | 
			
		||||
	/// </summary>
 | 
			
		||||
	public class CreateEntryThenCloseTask: AppTask
 | 
			
		||||
	{
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// extra key if only a URL is passed. optional.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public const String UrlKey = "CreateEntry_Url";
 | 
			
		||||
		
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// extra key if a json serialized key/value mapping is passed. optional.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// 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;
 | 
			
		||||
 | 
			
		||||
		public string Url
 | 
			
		||||
		{
 | 
			
		||||
			get;
 | 
			
		||||
			set;
 | 
			
		||||
		}
 | 
			
		||||
		/// <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)
 | 
			
		||||
		{
 | 
			
		||||
			Url = b.GetString(UrlKey);
 | 
			
		||||
			AllFields = b.GetString(AllFieldsKey);
 | 
			
		||||
			ProtectedFieldsList = b.GetStringArray(ProtectedFieldsListKey);
 | 
			
		||||
		}
 | 
			
		||||
		public override IEnumerable<IExtra> Extras 
 | 
			
		||||
		{ 
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				yield return new StringExtra { Key = UrlKey, Value = Url };
 | 
			
		||||
				if (Url != null)
 | 
			
		||||
					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)
 | 
			
		||||
		{
 | 
			
		||||
			newEntry.Strings.Set(PwDefs.UrlField, new ProtectedString(false, Url));
 | 
			
		||||
			if (Url != null)
 | 
			
		||||
			{
 | 
			
		||||
				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")]
 | 
			
		||||
	public class FileSelectActivity : ListActivity
 | 
			
		||||
	{
 | 
			
		||||
		private ActivityDesign _design;
 | 
			
		||||
		private readonly ActivityDesign _design;
 | 
			
		||||
		public FileSelectActivity (IntPtr javaReference, JniHandleOwnership transfer)
 | 
			
		||||
			: base(javaReference, transfer)
 | 
			
		||||
		{
 | 
			
		||||
@@ -136,7 +136,9 @@ namespace keepass2android
 | 
			
		||||
			EventHandler createNewButtonClick = (sender, e) =>
 | 
			
		||||
				{
 | 
			
		||||
					//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;
 | 
			
		||||
 | 
			
		||||
@@ -193,11 +195,11 @@ namespace keepass2android
 | 
			
		||||
		
 | 
			
		||||
		class MyViewBinder: Java.Lang.Object, SimpleCursorAdapter.IViewBinder
 | 
			
		||||
		{
 | 
			
		||||
			private Kp2aApp app;
 | 
			
		||||
			private readonly Kp2aApp _app;
 | 
			
		||||
 | 
			
		||||
			public MyViewBinder(Kp2aApp app)
 | 
			
		||||
			{
 | 
			
		||||
				this.app = app;
 | 
			
		||||
				_app = app;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			public bool SetViewValue(View view, ICursor cursor, int columnIndex)
 | 
			
		||||
@@ -207,7 +209,7 @@ namespace keepass2android
 | 
			
		||||
					String path = cursor.GetString(columnIndex);
 | 
			
		||||
					TextView textView = (TextView)view;
 | 
			
		||||
					IOConnectionInfo ioc = new IOConnectionInfo {Path = path};
 | 
			
		||||
					textView.Text = app.GetFileStorage(ioc).GetDisplayName(ioc);
 | 
			
		||||
					textView.Text = _app.GetFileStorage(ioc).GetDisplayName(ioc);
 | 
			
		||||
					textView.Tag = ioc.Path;
 | 
			
		||||
					return true;
 | 
			
		||||
				}
 | 
			
		||||
@@ -421,9 +423,7 @@ namespace keepass2android
 | 
			
		||||
			if (ShowRecentFiles() != _recentMode)
 | 
			
		||||
			{
 | 
			
		||||
				// Restart the activity
 | 
			
		||||
				Intent intent = Intent;
 | 
			
		||||
				StartActivity(intent);
 | 
			
		||||
				Finish();
 | 
			
		||||
				Recreate();
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -966,4 +966,7 @@
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <AndroidResource Include="Resources\drawable\ic_menu_copy_holo_light.png" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <AndroidResource Include="Resources\xml\searchable_debug.xml" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
@@ -36,9 +36,12 @@ namespace keepass2android
 | 
			
		||||
			return ((CheckBox)FindViewById(resId)).Checked;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private AppTask _appTask;
 | 
			
		||||
 | 
			
		||||
		protected override void OnCreate(Bundle bundle)
 | 
			
		||||
		{
 | 
			
		||||
			base.OnCreate(bundle);
 | 
			
		||||
			_appTask = AppTask.GetTaskInOnCreate(bundle, Intent);
 | 
			
		||||
			SetContentView(Resource.Layout.search);
 | 
			
		||||
			SearchParameters sp = new SearchParameters();
 | 
			
		||||
			PopulateCheckBox(Resource.Id.cbSearchInTitle, sp.SearchInTitles);
 | 
			
		||||
@@ -92,8 +95,11 @@ namespace keepass2android
 | 
			
		||||
			searchIntent.PutExtra("CaseSensitive", GetCheckBoxValue(Resource.Id.cbCaseSensitive));
 | 
			
		||||
			searchIntent.PutExtra("ExcludeExpired", GetCheckBoxValue(Resource.Id.cbExcludeExpiredEntries));
 | 
			
		||||
			searchIntent.PutExtra(SearchManager.Query, searchString);
 | 
			
		||||
			StartActivityForResult(searchIntent, 0);
 | 
			
		||||
			Finish();
 | 
			
		||||
			//forward appTask:
 | 
			
		||||
			_appTask.ToIntent(searchIntent);
 | 
			
		||||
 | 
			
		||||
			Util.FinishAndForward(this, searchIntent);
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -255,7 +255,7 @@ namespace keepass2android
 | 
			
		||||
                    // automatically bring up the Keyboard selection dialog
 | 
			
		||||
					if ((closeAfterCreate) && prefs.GetBoolean(GetString(Resource.String.OpenKp2aKeyboardAutomatically_key), Resources.GetBoolean(Resource.Boolean.OpenKp2aKeyboardAutomatically_default)))
 | 
			
		||||
                    {
 | 
			
		||||
                        ActivateKp2aKeyboard(this);        
 | 
			
		||||
                        ActivateKp2aKeyboard(this);
 | 
			
		||||
                    }
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user