/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. 

  Keepass2Android is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  Keepass2Android is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with Keepass2Android.  If not, see <http://www.gnu.org/licenses/>.
  */

using System;
using System.Collections.Generic;
using System.Linq;
using Android.AccessibilityServices;
using Android.Support.V4.App;
using Java.Util;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Widget;
using Android.Preferences;
using Android.Views.Accessibility;
using KeePassLib;
using KeePassLib.Utility;
using Android.Views.InputMethods;
using KeePass.Util.Spr;

namespace keepass2android
{
	/// <summary>
	/// Service to show the notifications to make the current entry accessible through clipboard or the KP2A keyboard.
	/// </summary>
	/// The name reflects only the possibility through clipboard because keyboard was introduced later.
	/// The notifications require to be displayed by a service in order to be kept when the activity is closed
	/// after searching for a URL.
	[Service]
	public class CopyToClipboardService : Service
	{
		class PasswordAccessNotificationBuilder
		{
			private readonly Context _ctx;
			private readonly NotificationManager _notificationManager;

			public PasswordAccessNotificationBuilder(Context ctx, NotificationManager notificationManager)
			{
				_ctx = ctx;
				_notificationManager = notificationManager;
			}

			private bool _hasPassword;
			private bool _hasUsername;
			private bool _hasKeyboard;

			public void AddPasswordAccess()
			{
				_hasPassword = true;
			}

			public void AddUsernameAccess()
			{
				_hasUsername = true;
			}

			public void AddKeyboardAccess()
			{
				_hasKeyboard = true;
			}

			public int CreateNotifications(string entryName)
			{
				if (((int) Build.VERSION.SdkInt < 16) ||
				    (PreferenceManager.GetDefaultSharedPreferences(_ctx)
				                      .GetBoolean(_ctx.GetString(Resource.String.ShowSeparateNotifications_key),
												  _ctx.Resources.GetBoolean(Resource.Boolean.ShowSeparateNotifications_default))))
				{
					return CreateSeparateNotifications(entryName);
				}
				else
				{
					return CreateCombinedNotification(entryName);
				}
				
			}

			private int CreateCombinedNotification(string entryName)
			{
				if ((!_hasUsername) && (!_hasPassword) && (!_hasKeyboard))
					return 0;

				NotificationCompat.Builder notificationBuilder;
				if (_hasKeyboard)
				{
					notificationBuilder = GetNotificationBuilder(Intents.CheckKeyboard, Resource.String.available_through_keyboard,
															Resource.Drawable.ic_notify_keyboard, entryName);
				}
				else
				{
					notificationBuilder = GetNotificationBuilder(null, Resource.String.entry_is_available, Resource.Drawable.ic_launcher_gray,
					                                   entryName);
				}
				
				//add action buttons to base notification:
				
				if (_hasUsername)
					notificationBuilder.AddAction(new NotificationCompat.Action(Resource.Drawable.ic_action_username, 
						_ctx.GetString(Resource.String.menu_copy_user), 
						GetPendingIntent(Intents.CopyUsername, Resource.String.menu_copy_user)));
				if (_hasPassword)
					notificationBuilder.AddAction(new NotificationCompat.Action(Resource.Drawable.ic_action_password, 
						_ctx.GetString(Resource.String.menu_copy_pass), 
						GetPendingIntent(Intents.CopyPassword, Resource.String.menu_copy_pass)));

				notificationBuilder.SetPriority((int)Android.App.NotificationPriority.Max);
				var notification = notificationBuilder.Build();
				notification.DeleteIntent = CreateDeleteIntent(NotifyCombined);
				_notificationManager.Notify(NotifyCombined, notification);

				return 1;
			}

			private int CreateSeparateNotifications(string entryName)
			{
				int numNotifications = 0;
				if (_hasPassword)
				{
					// only show notification if password is available
					Notification password = GetNotification(Intents.CopyPassword, Resource.String.copy_password,
					                                        Resource.Drawable.ic_action_password, entryName);
					numNotifications++;
					password.DeleteIntent = CreateDeleteIntent(NotifyPassword);
					_notificationManager.Notify(NotifyPassword, password);
				}
				if (_hasUsername)
				{
					// only show notification if username is available
					Notification username = GetNotification(Intents.CopyUsername, Resource.String.copy_username,
					                                        Resource.Drawable.ic_action_username, entryName);
					username.DeleteIntent = CreateDeleteIntent(NotifyUsername);
					_notificationManager.Notify(NotifyUsername, username);
					numNotifications++;
				}
				if (_hasKeyboard)
				{
					// only show notification if username is available
					Notification keyboard = GetNotification(Intents.CheckKeyboard, Resource.String.available_through_keyboard,
					                                        Resource.Drawable.ic_notify_keyboard, entryName);
					keyboard.DeleteIntent = CreateDeleteIntent(NotifyKeyboard);
					_notificationManager.Notify(NotifyKeyboard, keyboard);
					numNotifications++;
				}
				return numNotifications;
			}

			//creates a delete intent (started when notification is cancelled by user or something else)
			//requires different request codes for every item (otherwise the intents are identical)
			PendingIntent CreateDeleteIntent(int requestCode)
			{
				Intent intent = new Intent(ActionNotificationCancelled);
				Bundle extra = new Bundle();
				extra.PutInt("requestCode", requestCode);
				intent.PutExtras(extra);

				return PendingIntent.GetBroadcast(_ctx, requestCode, intent, PendingIntentFlags.CancelCurrent);
			}


			private Notification GetNotification(String intentText, int descResId, int drawableResId, String entryName)
			{
				var builder = GetNotificationBuilder(intentText, descResId, drawableResId, entryName);

				return builder.Build();
			}

			private NotificationCompat.Builder GetNotificationBuilder(string intentText, int descResId, int drawableResId, string entryName)
			{
				String desc = _ctx.GetString(descResId);

				String title = _ctx.GetString(Resource.String.app_name);
				if (!String.IsNullOrEmpty(entryName))
					title += " (" + entryName + ")";

				PendingIntent pending;
				if (intentText == null)
				{
					pending = PendingIntent.GetActivity(_ctx.ApplicationContext, 0, new Intent(), 0);
				}
				else
				{
					pending = GetPendingIntent(intentText, descResId);
				}

				var builder = new NotificationCompat.Builder(_ctx);
				builder.SetSmallIcon(drawableResId)
				       .SetContentText(desc)
				       .SetContentTitle(entryName)
				       .SetWhen(Java.Lang.JavaSystem.CurrentTimeMillis())
					   .SetTicker(entryName + ": " + desc)
					   .SetVisibility((int)Android.App.NotificationVisibility.Secret)
				       .SetContentIntent(pending);
				return builder;
			}

			private PendingIntent GetPendingIntent(string intentText, int descResId)
			{
				PendingIntent pending;
				Intent intent = new Intent(intentText);
				intent.SetPackage(_ctx.PackageName);
				pending = PendingIntent.GetBroadcast(_ctx, descResId, intent, PendingIntentFlags.CancelCurrent);
				return pending;
			}
		}

		public const int NotifyUsername = 1;
		public const int NotifyPassword = 2;
		public const int NotifyKeyboard = 3;
		public const int ClearClipboard = 4;
		public const int NotifyCombined = 5;

		static public void CopyValueToClipboardWithTimeout(Context ctx, string text)
		{
			Intent i = new Intent(ctx, typeof(CopyToClipboardService));
			i.SetAction(Intents.CopyStringToClipboard);
			i.PutExtra(_stringtocopy, text);
			ctx.StartService(i);
		}

		static public void ActivateKeyboard(Context ctx)
		{
			Intent i = new Intent(ctx, typeof(CopyToClipboardService));
			i.SetAction(Intents.ActivateKeyboard);
			ctx.StartService(i);
		}

		public static void CancelNotifications(Context ctx)
		{

			Intent i = new Intent(ctx, typeof(CopyToClipboardService));
			i.SetAction(Intents.ClearNotificationsAndData);
			ctx.StartService(i);
		}

		public CopyToClipboardService(IntPtr javaReference, JniHandleOwnership transfer)
			: base(javaReference, transfer)
		{
		}

		NotificationDeletedBroadcastReceiver _notificationDeletedBroadcastReceiver;
		StopOnLockBroadcastReceiver _stopOnLockBroadcastReceiver;

		public CopyToClipboardService()
		{


		}

		public override IBinder OnBind(Intent intent)
		{
			return null;
		}

		public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
		{
			Kp2aLog.Log("Received intent to provide access to entry");

			_stopOnLockBroadcastReceiver = new StopOnLockBroadcastReceiver(this);
			IntentFilter filter = new IntentFilter();
			filter.AddAction(Intents.DatabaseLocked);
			RegisterReceiver(_stopOnLockBroadcastReceiver, filter);

			if ((intent.Action == Intents.ShowNotification) || (intent.Action == Intents.UpdateKeyboard))
			{
				String uuidBytes = intent.GetStringExtra(EntryActivity.KeyEntry);
				String searchUrl = intent.GetStringExtra(SearchUrlTask.UrlToSearchKey);

				PwUuid entryId = PwUuid.Zero;
				if (uuidBytes != null)
					entryId = new PwUuid(MemUtil.HexStringToByteArray(uuidBytes));

				PwEntryOutput entry;
				try
				{
					if ((App.Kp2a.GetDb().LastOpenedEntry != null)
						&& (entryId.Equals(App.Kp2a.GetDb().LastOpenedEntry.Uuid)))
					{
						entry = App.Kp2a.GetDb().LastOpenedEntry;
					}
					else
					{
						entry = new PwEntryOutput(App.Kp2a.GetDb().Entries[entryId], App.Kp2a.GetDb().KpDatabase);
					}

				}
				catch (Exception)
				{
					//seems like restarting the service happened after closing the DB
					StopSelf();
					return StartCommandResult.NotSticky;
				}

				if (intent.Action == Intents.ShowNotification)
				{
					//first time opening the entry -> bring up the notifications
					bool closeAfterCreate = intent.GetBooleanExtra(EntryActivity.KeyCloseAfterCreate, false);
					DisplayAccessNotifications(entry, closeAfterCreate, searchUrl);
				}
				else //UpdateKeyboard
				{
#if !EXCLUDE_KEYBOARD
					//this action is received when the data in the entry has changed (e.g. by plugins)
					//update the keyboard data.
					//Check if keyboard is (still) available
					if (Keepass2android.Kbbridge.KeyboardData.EntryId == entry.Uuid.ToHexString())
						MakeAccessibleForKeyboard(entry, searchUrl);
#endif
				}
			}
			if (intent.Action == Intents.CopyStringToClipboard)
			{

				TimeoutCopyToClipboard(intent.GetStringExtra(_stringtocopy));
			}
			if (intent.Action == Intents.ActivateKeyboard)
			{
				ActivateKp2aKeyboard();
			}
			if (intent.Action == Intents.ClearNotificationsAndData)
			{
				ClearNotifications();
			}


			return StartCommandResult.RedeliverIntent;
		}

		private void OnLockDatabase()
		{
			Kp2aLog.Log("Stopping clipboard service due to database lock");

			StopSelf();
		}

		private NotificationManager _notificationManager;
		private int _numElementsToWaitFor;

		public override void OnDestroy()
		{
			Kp2aLog.Log("CopyToClipboardService.OnDestroy");

			// These members might never get initialized if the app timed out
			if (_stopOnLockBroadcastReceiver != null)
			{
				UnregisterReceiver(_stopOnLockBroadcastReceiver);
			}
			if (_notificationDeletedBroadcastReceiver != null)
			{
				UnregisterReceiver(_notificationDeletedBroadcastReceiver);
			}
			if (_notificationManager != null)
			{
				_notificationManager.Cancel(NotifyPassword);
				_notificationManager.Cancel(NotifyUsername);
				_notificationManager.Cancel(NotifyKeyboard);
				_notificationManager.Cancel(NotifyCombined);

				_numElementsToWaitFor = 0;
				ClearKeyboard(true);
			}
			if (_clearClipboardTask != null)
			{
				Kp2aLog.Log("Clearing clipboard due to stop CopyToClipboardService");
				_clearClipboardTask.Run();
			}

			Kp2aLog.Log("Destroyed Show-Notification-Receiver.");

			base.OnDestroy();
		}

		private const string ActionNotificationCancelled = "notification_cancelled";


		public void DisplayAccessNotifications(PwEntryOutput entry, bool closeAfterCreate, string searchUrl)
		{
			var hadKeyboardData = ClearNotifications();

			String entryName = entry.OutputStrings.ReadSafe(PwDefs.TitleField);

			ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
			var notBuilder = new PasswordAccessNotificationBuilder(this, _notificationManager);
			if (prefs.GetBoolean(GetString(Resource.String.CopyToClipboardNotification_key), Resources.GetBoolean(Resource.Boolean.CopyToClipboardNotification_default)))
			{

				if (entry.OutputStrings.ReadSafe(PwDefs.PasswordField).Length > 0)
				{
					notBuilder.AddPasswordAccess();

				}

				if (entry.OutputStrings.ReadSafe(PwDefs.UserNameField).Length > 0)
				{
					notBuilder.AddUsernameAccess();
				}
			}

			bool hasKeyboardDataNow = false;
			if (prefs.GetBoolean(GetString(Resource.String.UseKp2aKeyboard_key), Resources.GetBoolean(Resource.Boolean.UseKp2aKeyboard_default)))
			{

				//keyboard
				hasKeyboardDataNow = MakeAccessibleForKeyboard(entry, searchUrl);
				if (hasKeyboardDataNow)
				{
					notBuilder.AddKeyboardAccess();

					if (closeAfterCreate && Keepass2android.Autofill.AutoFillService.IsAvailable && (!Keepass2android.Autofill.AutoFillService.IsRunning))
					{
						if (!prefs.GetBoolean("has_asked_autofillservice", false))
						{
							var i = new Intent(this, typeof (ActivateAutoFillActivity));
							i.AddFlags(ActivityFlags.NewTask | ActivityFlags.ClearTask);
							StartActivity(i);
							prefs.Edit().PutBoolean("has_asked_autofillservice", true).Commit();
						}
						else ActivateKeyboardIfAppropriate(closeAfterCreate, prefs);
					}
					else ActivateKeyboardIfAppropriate(closeAfterCreate, prefs);
					
				}

			}

			if ((!hasKeyboardDataNow) && (hadKeyboardData))
			{
				ClearKeyboard(true); //this clears again and then (this is the point) broadcasts that we no longer have keyboard data
			}
			_numElementsToWaitFor = notBuilder.CreateNotifications(entryName);

			if (_numElementsToWaitFor == 0)
			{
				StopSelf();
				return;
			}

			IntentFilter filter = new IntentFilter();
			filter.AddAction(Intents.CopyUsername);
			filter.AddAction(Intents.CopyPassword);
			filter.AddAction(Intents.CheckKeyboard);

			//register receiver to get notified when notifications are discarded in which case we can shutdown the service
			_notificationDeletedBroadcastReceiver = new NotificationDeletedBroadcastReceiver(this);
			IntentFilter deletefilter = new IntentFilter();
			deletefilter.AddAction(ActionNotificationCancelled);
			RegisterReceiver(_notificationDeletedBroadcastReceiver, deletefilter);
		}

		public void ActivateKeyboardIfAppropriate(bool closeAfterCreate, ISharedPreferences prefs)
		{
			if (prefs.GetBoolean("kp2a_switch_rooted", false))
			{
				//switch rooted
				bool onlySwitchOnSearch = prefs.GetBoolean(
					GetString(Resource.String.OpenKp2aKeyboardAutomaticallyOnlyAfterSearch_key), false);
				if (closeAfterCreate || (!onlySwitchOnSearch))
				{
					ActivateKp2aKeyboard();
				}
			}
			else
			{
				//if the app is about to be closed again (e.g. after searching for a URL and returning to the browser:
				// automatically bring up the Keyboard selection dialog
				if ((closeAfterCreate) &&
				    prefs.GetBoolean(GetString(Resource.String.OpenKp2aKeyboardAutomatically_key),
					    Resources.GetBoolean(Resource.Boolean.OpenKp2aKeyboardAutomatically_default)))
				{
					ActivateKp2aKeyboard();
				}
			}
		}

		private bool ClearNotifications()
		{
			// Notification Manager
			_notificationManager = (NotificationManager)GetSystemService(NotificationService);

			_notificationManager.Cancel(NotifyPassword);
			_notificationManager.Cancel(NotifyUsername);
			_notificationManager.Cancel(NotifyKeyboard);
			_notificationManager.Cancel(NotifyCombined);
			_numElementsToWaitFor = 0;
			bool hadKeyboardData = ClearKeyboard(false); //do not broadcast if the keyboard was changed
			return hadKeyboardData;
		}

		bool MakeAccessibleForKeyboard(PwEntryOutput entry, string searchUrl)
		{
#if EXCLUDE_KEYBOARD
			return false;
#else
			bool hasData = false;
			Keepass2android.Kbbridge.KeyboardDataBuilder kbdataBuilder = new Keepass2android.Kbbridge.KeyboardDataBuilder();

			String[] keys = {PwDefs.UserNameField, 
				PwDefs.PasswordField, 
				PwDefs.UrlField,
				PwDefs.NotesField,
				PwDefs.TitleField
			};
			int[] resIds = {Resource.String.entry_user_name,
				Resource.String.entry_password,
				Resource.String.entry_url,
				Resource.String.entry_comment,
				Resource.String.entry_title };

			//add standard fields:
			int i=0;
			foreach (string key in keys)
			{
				String value = entry.OutputStrings.ReadSafe(key);

				if (value.Length > 0)
				{
					kbdataBuilder.AddString(key, GetString(resIds[i]), value);
					hasData = true;
				}
				i++;
			}
			//add additional fields:
			foreach (var pair in entry.OutputStrings)
			{
				var key = pair.Key;
				var value = pair.Value.ReadString();

				if (!PwDefs.IsStandardField(key)) {
					kbdataBuilder.AddString(pair.Key, pair.Key, value);
					hasData = true;
				}
			}


			kbdataBuilder.Commit();
			Keepass2android.Kbbridge.KeyboardData.EntryName = entry.OutputStrings.ReadSafe(PwDefs.TitleField);
			Keepass2android.Kbbridge.KeyboardData.EntryId = entry.Uuid.ToHexString();
			if (hasData)
				Keepass2android.Autofill.AutoFillService.NotifyNewData(searchUrl);

			return hasData;
#endif
		}


		public void OnWaitElementDeleted(int itemId)
		{
			_numElementsToWaitFor--;
			if (_numElementsToWaitFor <= 0)
			{
				StopSelf();
			}
			if ((itemId == NotifyKeyboard) || (itemId == NotifyCombined))
			{
				//keyboard notification was deleted -> clear entries in keyboard
				ClearKeyboard(true);
			}
		}

		bool ClearKeyboard(bool broadcastClear)
		{
#if !EXCLUDE_KEYBOARD
			Keepass2android.Kbbridge.KeyboardData.AvailableFields.Clear();
			Keepass2android.Kbbridge.KeyboardData.EntryName = null;
			bool hadData = Keepass2android.Kbbridge.KeyboardData.EntryId != null;
			Keepass2android.Kbbridge.KeyboardData.EntryId = null;

			if ((hadData) && broadcastClear)
				SendBroadcast(new Intent(Intents.KeyboardCleared));

			return hadData;
#else
			return false;
#endif
		}

		private readonly Timer _timer = new Timer();

		internal void TimeoutCopyToClipboard(String text)
		{
			Util.CopyToClipboard(this, text);

			ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
			String sClipClear = prefs.GetString(GetString(Resource.String.clipboard_timeout_key), GetString(Resource.String.clipboard_timeout_default));

			long clipClearTime = long.Parse(sClipClear);

			_clearClipboardTask = new ClearClipboardTask(this, text, _uiThreadCallback);
			if (clipClearTime > 0)
			{
				_numElementsToWaitFor++;
				_timer.Schedule(_clearClipboardTask, clipClearTime);
			}
		}

		// Task which clears the clipboard, and sends a toast to the foreground.
		private class ClearClipboardTask : TimerTask
		{

			private readonly String _clearText;
			private readonly CopyToClipboardService _service;
			private readonly Handler _handler;

			public ClearClipboardTask(CopyToClipboardService service, String clearText, Handler handler)
			{
				_clearText = clearText;
				_service = service;
				_handler = handler;
			}

			public override void Run()
			{
				String currentClip = Util.GetClipboard(_service);
				_handler.Post(() => _service.OnWaitElementDeleted(ClearClipboard));
				if (currentClip.Equals(_clearText))
				{
					Util.CopyToClipboard(_service, "");
					_handler.Post(() =>
					{
						Toast.MakeText(_service, Resource.String.ClearClipboard, ToastLength.Long).Show();
					});
				}
			}
		}


		// Setup to allow the toast to happen in the foreground
		readonly Handler _uiThreadCallback = new Handler();
		private ClearClipboardTask _clearClipboardTask;
		private const string _stringtocopy = "StringToCopy";



		private class StopOnLockBroadcastReceiver : BroadcastReceiver
		{
			readonly CopyToClipboardService _service;
			public StopOnLockBroadcastReceiver(CopyToClipboardService service)
			{
				_service = service;
			}

			public override void OnReceive(Context context, Intent intent)
			{
				switch (intent.Action)
				{
					case Intents.DatabaseLocked:
						_service.OnLockDatabase();
						break;
				}
			}
		}



		class NotificationDeletedBroadcastReceiver : BroadcastReceiver
		{
			readonly CopyToClipboardService _service;
			public NotificationDeletedBroadcastReceiver(CopyToClipboardService service)
			{
				_service = service;
			}

			#region implemented abstract members of BroadcastReceiver
			public override void OnReceive(Context context, Intent intent)
			{
				if (intent.Action == ActionNotificationCancelled)
				{
					_service.OnWaitElementDeleted(intent.Extras.GetInt("requestCode"));
				}
			}
			#endregion
		}

		internal void ActivateKp2aKeyboard()
		{
			string currentIme = Android.Provider.Settings.Secure.GetString(
								ContentResolver,
								Android.Provider.Settings.Secure.DefaultInputMethod);

			string kp2aIme = PackageName + "/keepass2android.softkeyboard.KP2AKeyboard";

			InputMethodManager imeManager = (InputMethodManager)ApplicationContext.GetSystemService(InputMethodService);
			if (imeManager == null)
			{
				Toast.MakeText(this, Resource.String.not_possible_im_picker, ToastLength.Long).Show();
				return;
			}

			if (currentIme == kp2aIme)
			{
				imeManager.ToggleSoftInput(ShowFlags.Forced, HideSoftInputFlags.None);
			}
			else
			{

				IList<InputMethodInfo> inputMethodProperties = imeManager.EnabledInputMethodList;

				if (!inputMethodProperties.Any(imi => imi.Id.Equals(kp2aIme)))
				{
					Toast.MakeText(this, Resource.String.please_activate_keyboard, ToastLength.Long).Show();
					Intent settingsIntent = new Intent(Android.Provider.Settings.ActionInputMethodSettings);
					settingsIntent.SetFlags(ActivityFlags.NewTask);
					StartActivity(settingsIntent);
				}
				else
				{
#if !EXCLUDE_KEYBOARD
	                Keepass2android.Kbbridge.ImeSwitcher.SwitchToKeyboard(this, kp2aIme, false);
#endif
				}
			}
		}


	}

	[BroadcastReceiver(Permission = "keepass2android." + AppNames.PackagePart + ".permission.CopyToClipboard")]
	[IntentFilter(new[] { Intents.CopyUsername, Intents.CopyPassword, Intents.CheckKeyboard })]
	class CopyToClipboardBroadcastReceiver : BroadcastReceiver
	{
		public CopyToClipboardBroadcastReceiver(IntPtr javaReference, JniHandleOwnership transfer)
			: base(javaReference, transfer)
		{
		}


		public CopyToClipboardBroadcastReceiver()
		{
		}

		public override void OnReceive(Context context, Intent intent)
		{
			String action = intent.Action;

			//check if we have a last opened entry
			//this should always be non-null, but if the OS has killed the app, it might occur.
			if (App.Kp2a.GetDb().LastOpenedEntry == null)
			{
				Intent i = new Intent(context, typeof(AppKilledInfo));
				i.SetFlags(ActivityFlags.ClearTask | ActivityFlags.NewTask);
				context.StartActivity(i);
				return;
			}

			if (action.Equals(Intents.CopyUsername))
			{
				String username = App.Kp2a.GetDb().LastOpenedEntry.OutputStrings.ReadSafe(PwDefs.UserNameField);
				if (username.Length > 0)
				{
					CopyToClipboardService.CopyValueToClipboardWithTimeout(context, username);
				}
				context.SendBroadcast(new Intent(Intent.ActionCloseSystemDialogs)); //close notification drawer
			}
			else if (action.Equals(Intents.CopyPassword))
			{
				String password = App.Kp2a.GetDb().LastOpenedEntry.OutputStrings.ReadSafe(PwDefs.PasswordField);
				if (password.Length > 0)
				{
					CopyToClipboardService.CopyValueToClipboardWithTimeout(context, password);
				}
				context.SendBroadcast(new Intent(Intent.ActionCloseSystemDialogs)); //close notification drawer
			}
			else if (action.Equals(Intents.CheckKeyboard))
			{
				CopyToClipboardService.ActivateKeyboard(context);
			}
		}

	};
}

