Compare commits
	
		
			2 Commits
		
	
	
		
			2869-fix-b
			...
			v1.12-r5-t
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					319d197d79 | ||
| 
						 | 
					b459e9f9a5 | 
@@ -56,6 +56,8 @@ using Android.Util;
 | 
			
		||||
using AndroidX.Core.Content;
 | 
			
		||||
using Google.Android.Material.Dialog;
 | 
			
		||||
using keepass2android;
 | 
			
		||||
using AndroidX.Core.App;
 | 
			
		||||
using Google.Android.Material.Snackbar;
 | 
			
		||||
 | 
			
		||||
namespace keepass2android
 | 
			
		||||
{
 | 
			
		||||
@@ -571,13 +573,41 @@ namespace keepass2android
 | 
			
		||||
            if (permissions.Length == 1 && permissions.First() == Android.Manifest.Permission.PostNotifications &&
 | 
			
		||||
                grantResults.First() == Permission.Granted)
 | 
			
		||||
            {
 | 
			
		||||
                StartNotificationsServiceAfterPermissionsCheck(requestCode == 1 /*requestCode is used to transfer this flag*/);
 | 
			
		||||
                if (!CopyToClipboardService.HasEntryNotificationPermissions(this, false))
 | 
			
		||||
                {
 | 
			
		||||
                    Intent intent = new Intent();
 | 
			
		||||
                    if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
 | 
			
		||||
                    {
 | 
			
		||||
                        intent.SetAction(Android.Provider.Settings.ActionAppNotificationSettings);
 | 
			
		||||
                        intent.PutExtra(Android.Provider.Settings.ExtraAppPackage, PackageName);
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
 | 
			
		||||
                    {
 | 
			
		||||
                        intent.SetAction(Android.Provider.Settings.ActionAppNotificationSettings);
 | 
			
		||||
                        intent.PutExtra("app_package", PackageName);
 | 
			
		||||
                        intent.PutExtra("app_uid", ApplicationInfo.Uid);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        intent.SetAction(Android.Provider.Settings.ActionApplicationDetailsSettings);
 | 
			
		||||
                        intent.AddCategory(Intent.CategoryDefault);
 | 
			
		||||
                        intent.SetData(Uri.Parse("package:" + PackageName));
 | 
			
		||||
                    }
 | 
			
		||||
                    StartActivity(intent);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
					Kp2aLog.Log($"StartNotificationsServiceAfterPermissionsCheck(activateKeyboard: requestCode == {requestCode}");
 | 
			
		||||
                    StartNotificationsServiceAfterPermissionsCheck(requestCode == 1 /*requestCode is used to transfer this flag*/);
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
 | 
			
		||||
        }
 | 
			
		||||
        internal void StartNotificationsService(bool activateKeyboard)
 | 
			
		||||
        {
 | 
			
		||||
			Kp2aLog.Log($"StartNotificationsService. ActivateKeyboard={activateKeyboard}");
 | 
			
		||||
            if (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(
 | 
			
		||||
                    GetString(Resource.String.CopyToClipboardNotification_key),
 | 
			
		||||
                    Resources.GetBoolean(Resource.Boolean.CopyToClipboardNotification_default)) == false
 | 
			
		||||
@@ -585,14 +615,18 @@ namespace keepass2android
 | 
			
		||||
                    GetString(Resource.String.UseKp2aKeyboard_key),
 | 
			
		||||
                    Resources.GetBoolean(Resource.Boolean.UseKp2aKeyboard_default)) == false)
 | 
			
		||||
            {
 | 
			
		||||
				//notifications are disabled
 | 
			
		||||
                //notifications are disabled
 | 
			
		||||
                Kp2aLog.Log($"StartNotificationsService. Notifications disabled. Returning.");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ((int)Build.VERSION.SdkInt < 33 || CheckSelfPermission(Android.Manifest.Permission.PostNotifications) ==
 | 
			
		||||
                Permission.Granted)
 | 
			
		||||
			{
 | 
			
		||||
                StartNotificationsServiceAfterPermissionsCheck(activateKeyboard);
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            if ((int)Build.VERSION.SdkInt < 33 || CopyToClipboardService.HasEntryNotificationPermissions(this, activateKeyboard))
 | 
			
		||||
            {
 | 
			
		||||
                Kp2aLog.Log($"StartNotificationsService. Permissions ok. activateKeyboard={activateKeyboard}");
 | 
			
		||||
 | 
			
		||||
                StartNotificationsServiceAfterPermissionsCheck(activateKeyboard); 
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -602,16 +636,40 @@ namespace keepass2android
 | 
			
		||||
            if (!ShouldShowRequestPermissionRationale(Android.Manifest.Permission.PostNotifications) //this menthod returns false if we haven't asked yet or if the user has denied permission too often
 | 
			
		||||
                && PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean("RequestedPostNotificationsPermission", false))//use a preference to tell the difference between "haven't asked yet" and "have asked too often"
 | 
			
		||||
            {
 | 
			
		||||
				//user has denied permission before. Do not show the dialog. User must give permission in the Android App settings.
 | 
			
		||||
                Kp2aLog.Log($"StartNotificationsService. Permissions not granted. Showing snackbar.");
 | 
			
		||||
                //user has denied permission before. Do not show the dialog. User must give permission in the Android App settings.
 | 
			
		||||
                var snackbar = Snackbar
 | 
			
		||||
                    .Make(SnackbarAnchorView, Resource.String.post_notifications_snackbar,
 | 
			
		||||
                        Snackbar.LengthIndefinite);
 | 
			
		||||
                snackbar.SetTextMaxLines(10);
 | 
			
		||||
                if ((int)Build.VERSION.SdkInt >= 23)
 | 
			
		||||
                {
 | 
			
		||||
 | 
			
		||||
                    snackbar.SetBackgroundTint(App.Context.GetColor(Resource.Color.md_theme_inverseSurface));
 | 
			
		||||
                    snackbar.SetTextColor(App.Context.GetColor(Resource.Color.md_theme_inverseOnSurface));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                snackbar.SetAction(Resource.String.post_notifications_snackbar_config, view => { ShowNotificationPermissionsDialog(activateKeyboard); });
 | 
			
		||||
 | 
			
		||||
                snackbar.Show();
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            ShowNotificationPermissionsDialog(activateKeyboard);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ShowNotificationPermissionsDialog(bool activateKeyboard)
 | 
			
		||||
        {
 | 
			
		||||
            Kp2aLog.Log($"ShowNotificationPermissionsDialog");
 | 
			
		||||
            new MaterialAlertDialogBuilder(this)
 | 
			
		||||
                .SetTitle(Resource.String.post_notifications_dialog_title)
 | 
			
		||||
                .SetMessage(Resource.String.post_notifications_dialog_message)
 | 
			
		||||
                .SetNegativeButton(Resource.String.post_notifications_dialog_disable, (sender, args) =>
 | 
			
		||||
                {
 | 
			
		||||
					//disable this dialog for the future by disabling the notification preferences
 | 
			
		||||
                    //disable this dialog for the future by disabling the notification preferences
 | 
			
		||||
                    var edit= PreferenceManager.GetDefaultSharedPreferences(this).Edit();
 | 
			
		||||
                    edit.PutBoolean(GetString(Resource.String.CopyToClipboardNotification_key), false);
 | 
			
		||||
                    edit.PutBoolean(GetString(Resource.String.UseKp2aKeyboard_key), false);
 | 
			
		||||
@@ -632,8 +690,6 @@ namespace keepass2android
 | 
			
		||||
                })
 | 
			
		||||
                .SetNeutralButton(Resource.String.post_notifications_dialog_notnow, (sender, args) => {  })
 | 
			
		||||
                .Show();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void StartNotificationsServiceAfterPermissionsCheck(bool activateKeyboard)
 | 
			
		||||
 
 | 
			
		||||
@@ -331,18 +331,14 @@ namespace keepass2android
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private bool hasRequestedKeyboardActivation = false;
 | 
			
		||||
        protected override void OnStart()
 | 
			
		||||
	    protected override void OnStart()
 | 
			
		||||
	    {
 | 
			
		||||
	        base.OnStart();
 | 
			
		||||
	        if (PreferenceManager.GetDefaultSharedPreferences(this)
 | 
			
		||||
	            .GetBoolean(GetString(Resource.String.UseKp2aKeyboardInKp2a_key), false)
 | 
			
		||||
                && (!hasRequestedKeyboardActivation))
 | 
			
		||||
	            .GetBoolean(GetString(Resource.String.UseKp2aKeyboardInKp2a_key), false))
 | 
			
		||||
	        {
 | 
			
		||||
                //only try this once. if the user clicks cancel, we don't want to ask again
 | 
			
		||||
				// (it may happen that the activity is restarted because of the NewTask flag immediately after the dialog)
 | 
			
		||||
                hasRequestedKeyboardActivation = true;
 | 
			
		||||
                CopyToClipboardService.ActivateKeyboard(this);
 | 
			
		||||
				Kp2aLog.Log("Activating keyboard in EntryEditActivity due to UseKp2aKeyboardInKp2a");
 | 
			
		||||
	            CopyToClipboardService.ActivateKeyboard(this);
 | 
			
		||||
	        }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
			android:versionCode="206"
 | 
			
		||||
			android:versionName="1.12-r5"
 | 
			
		||||
			android:versionCode="207"
 | 
			
		||||
			android:versionName="1.12-r5-test2848"
 | 
			
		||||
			package="keepass2android.keepass2android"
 | 
			
		||||
			xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
			android:installLocation="auto">
 | 
			
		||||
 
 | 
			
		||||
@@ -66,6 +66,7 @@ using Exception = System.Exception;
 | 
			
		||||
using String = System.String;
 | 
			
		||||
using Toolbar = AndroidX.AppCompat.Widget.Toolbar;
 | 
			
		||||
using AndroidX.Core.Content;
 | 
			
		||||
using Google.Android.Material.Snackbar;
 | 
			
		||||
 | 
			
		||||
namespace keepass2android
 | 
			
		||||
{
 | 
			
		||||
@@ -131,8 +132,7 @@ namespace keepass2android
 | 
			
		||||
		ISharedPreferences _prefs;
 | 
			
		||||
 | 
			
		||||
		private bool _starting;
 | 
			
		||||
        private bool _resumeCompleted;
 | 
			
		||||
        private OtpInfo _otpInfo;
 | 
			
		||||
		private OtpInfo _otpInfo;
 | 
			
		||||
		private IOConnectionInfo _otpAuxIoc;
 | 
			
		||||
        private ChallengeInfo _chalInfo;
 | 
			
		||||
        private byte[] _challengeSecret;
 | 
			
		||||
@@ -801,6 +801,8 @@ namespace keepass2android
 | 
			
		||||
 | 
			
		||||
            _password = i.GetStringExtra(KeyPassword) ?? "";
 | 
			
		||||
            if (!KeyProviderTypes.Any())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            {
 | 
			
		||||
                SetKeyProviderFromString(LoadKeyProviderStringForIoc(_ioConnection.Path));
 | 
			
		||||
            }
 | 
			
		||||
@@ -1253,7 +1255,7 @@ namespace keepass2android
 | 
			
		||||
							case 6:
 | 
			
		||||
							    KeyProviderTypes.Add(KeyProviders.ChallengeXC);
 | 
			
		||||
							    break;
 | 
			
		||||
                            case 7:
 | 
			
		||||
						        case 7:
 | 
			
		||||
						            //don't set to "" to prevent losing the filename. (ItemSelected is also called during recreation!)
 | 
			
		||||
							    Kp2aLog.Log("key file length before: " + _keyFile?.Length);
 | 
			
		||||
						            _keyFile = (FindViewById(Resource.Id.label_keyfilename).Tag ?? "").ToString();
 | 
			
		||||
@@ -1568,20 +1570,15 @@ namespace keepass2android
 | 
			
		||||
 | 
			
		||||
            base.OnPause();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        private bool hasRequestedKeyboardActivation = false;
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        protected override void OnStart()
 | 
			
		||||
		protected override void OnStart()
 | 
			
		||||
		{
 | 
			
		||||
			base.OnStart();
 | 
			
		||||
			_starting = true;
 | 
			
		||||
 | 
			
		||||
		    if (PreferenceManager.GetDefaultSharedPreferences(this)
 | 
			
		||||
		        .GetBoolean(GetString(Resource.String.UseKp2aKeyboardInKp2a_key), false)
 | 
			
		||||
                && !hasRequestedKeyboardActivation)
 | 
			
		||||
            {
 | 
			
		||||
                hasRequestedKeyboardActivation = true;
 | 
			
		||||
		        .GetBoolean(GetString(Resource.String.UseKp2aKeyboardInKp2a_key), false))
 | 
			
		||||
		    {
 | 
			
		||||
                Kp2aLog.Log("Activating keyboard in PasswordActivity due to UseKp2aKeyboardInKp2a");
 | 
			
		||||
                CopyToClipboardService.ActivateKeyboard(this);
 | 
			
		||||
		    }
 | 
			
		||||
 | 
			
		||||
@@ -1647,65 +1644,60 @@ namespace keepass2android
 | 
			
		||||
            if (intent != null)
 | 
			
		||||
            {
 | 
			
		||||
				if (intent.HasExtra(Intents.OtpExtraKey))
 | 
			
		||||
				{
 | 
			
		||||
					string otp = intent.GetStringExtra(Intents.OtpExtraKey);
 | 
			
		||||
					_keepPasswordInOnResume = true;
 | 
			
		||||
					if (KeyProviderTypes.Contains(KeyProviders.Otp))
 | 
			
		||||
					{
 | 
			
		||||
 | 
			
		||||
						if (_otpInfo == null)
 | 
			
		||||
						{
 | 
			
		||||
							//Entering OTPs not yet initialized:
 | 
			
		||||
							_pendingOtps.Add(otp);
 | 
			
		||||
							UpdateKeyProviderUiState();
 | 
			
		||||
						}
 | 
			
		||||
						else
 | 
			
		||||
						{
 | 
			
		||||
							//Entering OTPs is initialized. Write OTP into first empty field:
 | 
			
		||||
							bool foundEmptyField = false;
 | 
			
		||||
							foreach (int otpId in _otpTextViewIds)
 | 
			
		||||
							{
 | 
			
		||||
								EditText otpEdit = FindViewById<EditText>(otpId);
 | 
			
		||||
								if ((otpEdit.Visibility == ViewStates.Visible) && String.IsNullOrEmpty(otpEdit.Text))
 | 
			
		||||
								{
 | 
			
		||||
									otpEdit.Text = otp;
 | 
			
		||||
									foundEmptyField = true;
 | 
			
		||||
									break;
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
							//did we find a field?
 | 
			
		||||
							if (!foundEmptyField)
 | 
			
		||||
							{
 | 
			
		||||
								App.Kp2a.ShowMessage(this, GetString(Resource.String.otp_discarded_no_space), MessageSeverity.Error);
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						Spinner passwordModeSpinner = FindViewById<Spinner>(Resource.Id.password_mode_spinner);
 | 
			
		||||
						if (passwordModeSpinner.SelectedItemPosition != (int)KeyProviders.Otp)
 | 
			
		||||
						{
 | 
			
		||||
							passwordModeSpinner.SetSelection((int)KeyProviders.Otp);
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					else
 | 
			
		||||
					{
 | 
			
		||||
						//assume the key should be used as static password
 | 
			
		||||
						FindViewById<EditText>(Resource.Id.password_edit).Text += otp;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
                    // if the activity is launched twice and the first initialization hasn't even finished, we cannot 
 | 
			
		||||
                    // reset the state and re-initialize the activity.
 | 
			
		||||
					// This can happen with autofill in some cases (#2869)
 | 
			
		||||
                    if (_resumeCompleted)
 | 
			
		||||
                {
 | 
			
		||||
                    string otp = intent.GetStringExtra(Intents.OtpExtraKey);
 | 
			
		||||
                    _keepPasswordInOnResume = true;
 | 
			
		||||
                    if (KeyProviderTypes.Contains(KeyProviders.Otp))
 | 
			
		||||
                    {
 | 
			
		||||
                        ResetState();
 | 
			
		||||
                        GetIocFromLaunchIntent(intent);
 | 
			
		||||
                        InitializeAfterSetIoc();
 | 
			
		||||
                        OnStart();
 | 
			
		||||
 | 
			
		||||
                        if (_otpInfo == null)
 | 
			
		||||
                        {
 | 
			
		||||
                            //Entering OTPs not yet initialized:
 | 
			
		||||
                            _pendingOtps.Add(otp);
 | 
			
		||||
                            UpdateKeyProviderUiState();
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            //Entering OTPs is initialized. Write OTP into first empty field:
 | 
			
		||||
                            bool foundEmptyField = false;
 | 
			
		||||
                            foreach (int otpId in _otpTextViewIds)
 | 
			
		||||
                            {
 | 
			
		||||
                                EditText otpEdit = FindViewById<EditText>(otpId);
 | 
			
		||||
                                if ((otpEdit.Visibility == ViewStates.Visible) && String.IsNullOrEmpty(otpEdit.Text))
 | 
			
		||||
                                {
 | 
			
		||||
                                    otpEdit.Text = otp;
 | 
			
		||||
                                    foundEmptyField = true;
 | 
			
		||||
                                    break;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                            //did we find a field?
 | 
			
		||||
                            if (!foundEmptyField)
 | 
			
		||||
                            {
 | 
			
		||||
                                App.Kp2a.ShowMessage(this, GetString(Resource.String.otp_discarded_no_space),  MessageSeverity.Error);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        Spinner passwordModeSpinner = FindViewById<Spinner>(Resource.Id.password_mode_spinner);
 | 
			
		||||
                        if (passwordModeSpinner.SelectedItemPosition != (int)KeyProviders.Otp)
 | 
			
		||||
                        {
 | 
			
		||||
                            passwordModeSpinner.SetSelection((int)KeyProviders.Otp);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
					
 | 
			
		||||
				}
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        //assume the key should be used as static password
 | 
			
		||||
                        FindViewById<EditText>(Resource.Id.password_edit).Text += otp;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    ResetState();
 | 
			
		||||
                    GetIocFromLaunchIntent(intent);
 | 
			
		||||
					InitializeAfterSetIoc();
 | 
			
		||||
                    OnStart();
 | 
			
		||||
                }
 | 
			
		||||
			}
 | 
			
		||||
	
 | 
			
		||||
		}
 | 
			
		||||
@@ -1744,150 +1736,185 @@ namespace keepass2android
 | 
			
		||||
 | 
			
		||||
        protected override View? SnackbarAnchorView => FindViewById(Resource.Id.main_content);
 | 
			
		||||
 | 
			
		||||
		protected override void OnResume()
 | 
			
		||||
		{
 | 
			
		||||
			base.OnResume();
 | 
			
		||||
        protected override void OnResume()
 | 
			
		||||
        {
 | 
			
		||||
            base.OnResume();
 | 
			
		||||
            
 | 
			
		||||
            _activityDesign.ReapplyTheme();
 | 
			
		||||
 | 
			
		||||
			_activityDesign.ReapplyTheme();
 | 
			
		||||
            Kp2aLog.Log("starting: " + _starting + ", Finishing: " + IsFinishing + ", _performingLoad: " +
 | 
			
		||||
                        _performingLoad);
 | 
			
		||||
 | 
			
		||||
			Kp2aLog.Log("starting: " + _starting + ", Finishing: " + IsFinishing + ", _performingLoad: " +
 | 
			
		||||
						_performingLoad);
 | 
			
		||||
            CheckBox cbOfflineMode = (CheckBox)FindViewById(Resource.Id.work_offline);
 | 
			
		||||
            App.Kp2a.OfflineMode =
 | 
			
		||||
                cbOfflineMode.Checked =
 | 
			
		||||
                    App.Kp2a
 | 
			
		||||
                        .OfflineModePreference; //this won't overwrite new user settings because every change is directly saved in settings
 | 
			
		||||
            LinearLayout offlineModeContainer = FindViewById<LinearLayout>(Resource.Id.work_offline_container);
 | 
			
		||||
            var cachingFileStorage = App.Kp2a.GetFileStorage(_ioConnection) as CachingFileStorage;
 | 
			
		||||
            if ((cachingFileStorage != null) && cachingFileStorage.IsCached(_ioConnection))
 | 
			
		||||
            {
 | 
			
		||||
                offlineModeContainer.Visibility = ViewStates.Visible;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                offlineModeContainer.Visibility = ViewStates.Gone;
 | 
			
		||||
                App.Kp2a.OfflineMode = false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
			CheckBox cbOfflineMode = (CheckBox)FindViewById(Resource.Id.work_offline);
 | 
			
		||||
			App.Kp2a.OfflineMode =
 | 
			
		||||
				cbOfflineMode.Checked =
 | 
			
		||||
					App.Kp2a
 | 
			
		||||
						.OfflineModePreference; //this won't overwrite new user settings because every change is directly saved in settings
 | 
			
		||||
			LinearLayout offlineModeContainer = FindViewById<LinearLayout>(Resource.Id.work_offline_container);
 | 
			
		||||
			var cachingFileStorage = App.Kp2a.GetFileStorage(_ioConnection) as CachingFileStorage;
 | 
			
		||||
			if ((cachingFileStorage != null) && cachingFileStorage.IsCached(_ioConnection))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            View killButton = FindViewById(Resource.Id.kill_app);
 | 
			
		||||
            if (PreferenceManager.GetDefaultSharedPreferences(this)
 | 
			
		||||
                .GetBoolean(GetString(Resource.String.show_kill_app_key), false))
 | 
			
		||||
            {
 | 
			
		||||
                killButton.Click += (sender, args) =>
 | 
			
		||||
                {
 | 
			
		||||
                    _killOnDestroy = true;
 | 
			
		||||
                    SetResult(Result.Canceled);
 | 
			
		||||
                    Finish();
 | 
			
		||||
 | 
			
		||||
                };
 | 
			
		||||
                killButton.Visibility = ViewStates.Visible;
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                killButton.Visibility = ViewStates.Gone;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            TryGetOtpFromClipboard();
 | 
			
		||||
 | 
			
		||||
            if (!_keepPasswordInOnResume)
 | 
			
		||||
            {
 | 
			
		||||
                if (
 | 
			
		||||
                    _lastOnPauseTime <
 | 
			
		||||
                    DateTime.Now -
 | 
			
		||||
                    TimeSpan.FromSeconds(
 | 
			
		||||
                        5) //only clear when user left the app for more than 5 seconds (allows to use Yubiclip, also allows to switch shortly to another app)
 | 
			
		||||
                    &&
 | 
			
		||||
                    PreferenceManager.GetDefaultSharedPreferences(this)
 | 
			
		||||
                        .GetBoolean(GetString(Resource.String.ClearPasswordOnLeave_key), true))
 | 
			
		||||
                {
 | 
			
		||||
                    ClearEnteredPassword();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            _keepPasswordInOnResume = false;
 | 
			
		||||
 | 
			
		||||
            MakePasswordMaskedOrVisible();
 | 
			
		||||
 | 
			
		||||
            UpdateOkButtonState();
 | 
			
		||||
 | 
			
		||||
            if (KeyProviderTypes.Contains(KeyProviders.Challenge))
 | 
			
		||||
            {
 | 
			
		||||
                FindViewById(Resource.Id.otpInitView).Visibility =
 | 
			
		||||
                    _challengeSecret == null ? ViewStates.Visible : ViewStates.Gone;
 | 
			
		||||
            }
 | 
			
		||||
			/*
 | 
			
		||||
            Snackbar snackbar = Snackbar
 | 
			
		||||
                .Make(FindViewById(Resource.Id.main_content),
 | 
			
		||||
                    "snack snack snack snack snack snack snack snack snack snack snack snack snack snack snacksnack snack snacksnack snack snacksnack snack snack snack snack snack snack snack snack snack snack snack snack snack snack snacksnack snack snacksnack snack snacksnack  snack snack snack snack snacksnack snack snack ",
 | 
			
		||||
                    Snackbar.LengthLong);
 | 
			
		||||
            snackbar.SetTextMaxLines(5);
 | 
			
		||||
            snackbar.SetBackgroundTint(GetColor(Resource.Color.md_theme_secondaryContainer));
 | 
			
		||||
            snackbar.SetTextColor(GetColor(Resource.Color.md_theme_onSecondaryContainer));
 | 
			
		||||
            snackbar.SetAction("dismiss",
 | 
			
		||||
                view => snackbar.SetBackgroundTint(GetColor(Resource.Color.md_theme_surfaceContainer)));
 | 
			
		||||
 | 
			
		||||
            snackbar.Show();
 | 
			
		||||
 | 
			
		||||
            new Handler().PostDelayed(() =>
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
                Snackbar snackbar2 = Snackbar
 | 
			
		||||
                    .Make(FindViewById(Resource.Id.main_content), "snack snack snack ",
 | 
			
		||||
                        Snackbar.LengthLong);
 | 
			
		||||
                snackbar2.SetTextMaxLines(5);
 | 
			
		||||
                snackbar2.SetBackgroundTint(GetColor(Resource.Color.md_theme_errorContainer));
 | 
			
		||||
                snackbar2.SetTextColor(GetColor(Resource.Color.md_theme_onErrorContainer));
 | 
			
		||||
                snackbar2.Show();
 | 
			
		||||
            }, 1500);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            new Handler().PostDelayed(() =>
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
                Snackbar snackbar2 = Snackbar
 | 
			
		||||
                    .Make(FindViewById(Resource.Id.main_content), "snack snack warn ",
 | 
			
		||||
                        Snackbar.LengthLong);
 | 
			
		||||
                snackbar2.SetTextMaxLines(5);
 | 
			
		||||
                snackbar2.SetBackgroundTint(GetColor(Resource.Color.md_theme_inverseSurface));
 | 
			
		||||
                snackbar2.SetTextColor(GetColor(Resource.Color.md_theme_inverseOnSurface));
 | 
			
		||||
                snackbar2.Show();
 | 
			
		||||
            }, 2500);*/
 | 
			
		||||
 | 
			
		||||
            //use !IsFinishing to make sure we're not starting another activity when we're already finishing (e.g. due to TaskComplete in OnActivityResult)
 | 
			
		||||
            //use !performingLoad to make sure we're not already loading the database (after ActivityResult from File-Prepare-Activity; this would cause _loadDbFileTask to exist when we reload later!)
 | 
			
		||||
            if ( !IsFinishing && !_performingLoad)  
 | 
			
		||||
			{
 | 
			
		||||
				offlineModeContainer.Visibility = ViewStates.Visible;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				offlineModeContainer.Visibility = ViewStates.Gone;
 | 
			
		||||
				App.Kp2a.OfflineMode = false;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
			View killButton = FindViewById(Resource.Id.kill_app);
 | 
			
		||||
			if (PreferenceManager.GetDefaultSharedPreferences(this)
 | 
			
		||||
				.GetBoolean(GetString(Resource.String.show_kill_app_key), false))
 | 
			
		||||
			{
 | 
			
		||||
				killButton.Click += (sender, args) =>
 | 
			
		||||
				{
 | 
			
		||||
					_killOnDestroy = true;
 | 
			
		||||
					SetResult(Result.Canceled);
 | 
			
		||||
					Finish();
 | 
			
		||||
 | 
			
		||||
				};
 | 
			
		||||
				killButton.Visibility = ViewStates.Visible;
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				killButton.Visibility = ViewStates.Gone;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			TryGetOtpFromClipboard();
 | 
			
		||||
 | 
			
		||||
			if (!_keepPasswordInOnResume)
 | 
			
		||||
			{
 | 
			
		||||
				if (
 | 
			
		||||
					_lastOnPauseTime <
 | 
			
		||||
					DateTime.Now -
 | 
			
		||||
					TimeSpan.FromSeconds(
 | 
			
		||||
						5) //only clear when user left the app for more than 5 seconds (allows to use Yubiclip, also allows to switch shortly to another app)
 | 
			
		||||
					&&
 | 
			
		||||
					PreferenceManager.GetDefaultSharedPreferences(this)
 | 
			
		||||
						.GetBoolean(GetString(Resource.String.ClearPasswordOnLeave_key), true))
 | 
			
		||||
				{
 | 
			
		||||
					ClearEnteredPassword();
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
			_keepPasswordInOnResume = false;
 | 
			
		||||
 | 
			
		||||
			MakePasswordMaskedOrVisible();
 | 
			
		||||
 | 
			
		||||
			UpdateOkButtonState();
 | 
			
		||||
 | 
			
		||||
			if (KeyProviderTypes.Contains(KeyProviders.Challenge))
 | 
			
		||||
			{
 | 
			
		||||
				FindViewById(Resource.Id.otpInitView).Visibility =
 | 
			
		||||
					_challengeSecret == null ? ViewStates.Visible : ViewStates.Gone;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			//use !IsFinishing to make sure we're not starting another activity when we're already finishing (e.g. due to TaskComplete in OnActivityResult)
 | 
			
		||||
			//use !performingLoad to make sure we're not already loading the database (after ActivityResult from File-Prepare-Activity; this would cause _loadDbFileTask to exist when we reload later!)
 | 
			
		||||
			if (!IsFinishing && !_performingLoad)
 | 
			
		||||
			{
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
				// OnResume is run every time the activity comes to the foreground. This code should only run when the activity is started (OnStart), but must
 | 
			
		||||
				
 | 
			
		||||
				
 | 
			
		||||
			    // OnResume is run every time the activity comes to the foreground. This code should only run when the activity is started (OnStart), but must
 | 
			
		||||
				// be run in OnResume rather than OnStart so that it always occurrs after OnActivityResult (when re-creating a killed activity, OnStart occurs before OnActivityResult)
 | 
			
		||||
				if (_starting)
 | 
			
		||||
				{
 | 
			
		||||
			    if (_starting)
 | 
			
		||||
			    {
 | 
			
		||||
 | 
			
		||||
					_starting = false;
 | 
			
		||||
			        _starting = false;
 | 
			
		||||
 | 
			
		||||
					//database not yet loaded.
 | 
			
		||||
			        //database not yet loaded.
 | 
			
		||||
 | 
			
		||||
					//check if pre-loading is enabled but wasn't started yet:
 | 
			
		||||
					if (_loadDbFileTask == null &&
 | 
			
		||||
						_prefs.GetBoolean(GetString(Resource.String.PreloadDatabaseEnabled_key), true))
 | 
			
		||||
					{
 | 
			
		||||
						// Create task to kick off file loading while the user enters the password
 | 
			
		||||
						_loadDbFileTask = Task.Factory.StartNew(PreloadDbFile);
 | 
			
		||||
						_loadDbTaskOffline = App.Kp2a.OfflineMode;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			        //check if pre-loading is enabled but wasn't started yet:
 | 
			
		||||
			        if (_loadDbFileTask == null &&
 | 
			
		||||
			            _prefs.GetBoolean(GetString(Resource.String.PreloadDatabaseEnabled_key), true))
 | 
			
		||||
			        {
 | 
			
		||||
			            // Create task to kick off file loading while the user enters the password
 | 
			
		||||
			            _loadDbFileTask = Task.Factory.StartNew(PreloadDbFile);
 | 
			
		||||
			            _loadDbTaskOffline = App.Kp2a.OfflineMode;
 | 
			
		||||
			        }
 | 
			
		||||
			    }
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (compositeKeyForImmediateLoad != null)
 | 
			
		||||
			{
 | 
			
		||||
				//reload the database (without most other stuff performed in PerformLoadDatabase.
 | 
			
		||||
				// We're assuming that the db file (and if appropriate also the key file) are still available 
 | 
			
		||||
				// and there's no need to re-init the file storage. if it is, loading will fail and the user has 
 | 
			
		||||
				// to retry with typing the full password, but that's intended to avoid showing the password to a 
 | 
			
		||||
				// a potentially unauthorized user (feature request https://keepass2android.codeplex.com/workitem/274)
 | 
			
		||||
				Handler handler = new Handler();
 | 
			
		||||
				OnFinish onFinish = new AfterLoad(handler, this, _ioConnection);
 | 
			
		||||
				_performingLoad = true;
 | 
			
		||||
				LoadDb task = new LoadDb(this, App.Kp2a, _ioConnection, _loadDbFileTask, compositeKeyForImmediateLoad, GetKeyProviderString(),
 | 
			
		||||
					onFinish, false, _makeCurrent);
 | 
			
		||||
				_loadDbFileTask = null; // prevent accidental re-use
 | 
			
		||||
				new ProgressTask(App.Kp2a, this, task).Run();
 | 
			
		||||
				compositeKeyForImmediateLoad = null; //don't reuse or keep in memory
 | 
			
		||||
		    if (compositeKeyForImmediateLoad != null)
 | 
			
		||||
		    {
 | 
			
		||||
		        //reload the database (without most other stuff performed in PerformLoadDatabase.
 | 
			
		||||
		        // We're assuming that the db file (and if appropriate also the key file) are still available 
 | 
			
		||||
		        // and there's no need to re-init the file storage. if it is, loading will fail and the user has 
 | 
			
		||||
		        // to retry with typing the full password, but that's intended to avoid showing the password to a 
 | 
			
		||||
		        // a potentially unauthorized user (feature request https://keepass2android.codeplex.com/workitem/274)
 | 
			
		||||
		        Handler handler = new Handler();
 | 
			
		||||
		        OnFinish onFinish = new AfterLoad(handler, this, _ioConnection);
 | 
			
		||||
		        _performingLoad = true;
 | 
			
		||||
                LoadDb task = new LoadDb(this, App.Kp2a, _ioConnection, _loadDbFileTask, compositeKeyForImmediateLoad, GetKeyProviderString(),
 | 
			
		||||
		            onFinish, false, _makeCurrent);
 | 
			
		||||
		        _loadDbFileTask = null; // prevent accidental re-use
 | 
			
		||||
		        new ProgressTask(App.Kp2a, this, task).Run();
 | 
			
		||||
		        compositeKeyForImmediateLoad = null; //don't reuse or keep in memory
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				bool showKeyboard = true;
 | 
			
		||||
		    }
 | 
			
		||||
		    else
 | 
			
		||||
		    {
 | 
			
		||||
		        bool showKeyboard = true;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
				EditText pwd = (EditText)FindViewById(Resource.Id.password_edit);
 | 
			
		||||
				pwd.PostDelayed(() =>
 | 
			
		||||
				{
 | 
			
		||||
					InputMethodManager keyboard = (InputMethodManager)GetSystemService(InputMethodService);
 | 
			
		||||
					if (showKeyboard)
 | 
			
		||||
					{
 | 
			
		||||
						pwd.RequestFocus();
 | 
			
		||||
						keyboard.ShowSoftInput(pwd, 0);
 | 
			
		||||
					}
 | 
			
		||||
					else
 | 
			
		||||
						keyboard.HideSoftInputFromWindow(pwd.WindowToken, HideSoftInputFlags.ImplicitOnly);
 | 
			
		||||
				}, 50);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			_resumeCompleted = true;
 | 
			
		||||
		       
 | 
			
		||||
		        EditText pwd = (EditText) FindViewById(Resource.Id.password_edit);
 | 
			
		||||
		        pwd.PostDelayed(() =>
 | 
			
		||||
		        {
 | 
			
		||||
		            InputMethodManager keyboard = (InputMethodManager) GetSystemService(InputMethodService);
 | 
			
		||||
                    if (showKeyboard)
 | 
			
		||||
                    {
 | 
			
		||||
                        pwd.RequestFocus();
 | 
			
		||||
                        keyboard.ShowSoftInput(pwd, 0);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
		                keyboard.HideSoftInputFromWindow(pwd.WindowToken, HideSoftInputFlags.ImplicitOnly);
 | 
			
		||||
		        }, 50);
 | 
			
		||||
		    }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
	    private void TryGetOtpFromClipboard()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,4 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
                                                     android:id="@+id/main_content"
 | 
			
		||||
                                                     android:layout_width="match_parent"
 | 
			
		||||
                                                     android:layout_height="match_parent"
 | 
			
		||||
                                                     android:fitsSystemWindows="true">
 | 
			
		||||
<LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
               xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
               android:orientation="vertical"
 | 
			
		||||
@@ -19,7 +14,6 @@
 | 
			
		||||
               android:text="@string/switch_ime_text" />
 | 
			
		||||
 | 
			
		||||
    <Button 
 | 
			
		||||
      
 | 
			
		||||
      android:id="@+id/btn_reopen"
 | 
			
		||||
      android:layout_width="match_parent"
 | 
			
		||||
               android:layout_height="wrap_content"
 | 
			
		||||
@@ -31,51 +25,4 @@
 | 
			
		||||
      android:layout_height="wrap_content"
 | 
			
		||||
      android:text="@string/cancel" />
 | 
			
		||||
 | 
			
		||||
    <LinearLayout android:orientation="vertical"
 | 
			
		||||
            android:paddingTop="64dp"
 | 
			
		||||
            android:id="@+id/settings_notes_container"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content">
 | 
			
		||||
            <TextView
 | 
			
		||||
              android:paddingTop="12dp"
 | 
			
		||||
                android:id="@+id/note_kp2a_switch_rooted"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:text="@string/autoswitch_enabled_but_not_setup"
 | 
			
		||||
                />
 | 
			
		||||
 | 
			
		||||
            <TextView
 | 
			
		||||
              android:paddingTop="12dp"
 | 
			
		||||
              android:id="@+id/note_AutoFillTotp_prefs_ActivateKeyboard"
 | 
			
		||||
              android:layout_width="match_parent"
 | 
			
		||||
              android:layout_height="wrap_content"
 | 
			
		||||
              android:text="@string/switch_keyboard_for_totp_enabled"
 | 
			
		||||
            />
 | 
			
		||||
 | 
			
		||||
            <TextView
 | 
			
		||||
              android:paddingTop="12dp"
 | 
			
		||||
              android:id="@+id/note_UseKp2aKeyboardInKp2a"
 | 
			
		||||
              android:layout_width="match_parent"
 | 
			
		||||
              android:layout_height="wrap_content"
 | 
			
		||||
              android:text="@string/switch_keyboard_inside_kp2a_enabled"
 | 
			
		||||
            />
 | 
			
		||||
 | 
			
		||||
            <TextView
 | 
			
		||||
                android:id="@+id/note_OpenKp2aKeyboardAutomatically"
 | 
			
		||||
              android:paddingTop="12dp"
 | 
			
		||||
              android:layout_width="match_parent"
 | 
			
		||||
              android:layout_height="wrap_content"
 | 
			
		||||
              android:text="@string/switch_keyboard_on_search_enabled"
 | 
			
		||||
            />
 | 
			
		||||
            
 | 
			
		||||
            <Button 
 | 
			
		||||
              style="?attr/materialButtonOutlinedStyle"
 | 
			
		||||
              android:id="@+id/btn_open_settings"
 | 
			
		||||
              android:layout_width="match_parent"
 | 
			
		||||
              android:layout_height="wrap_content"
 | 
			
		||||
              android:text="@string/IconVisibilityInfo_Android8_btnSettings" />
 | 
			
		||||
 | 
			
		||||
            </LinearLayout>
 | 
			
		||||
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
 | 
			
		||||
@@ -200,7 +200,7 @@
 | 
			
		||||
    <item>System</item>
 | 
			
		||||
	</string-array>
 | 
			
		||||
	
 | 
			
		||||
	<string name="AcceptAllServerCertificates_default">ERROR</string>
 | 
			
		||||
	<string name="AcceptAllServerCertificates_default">WARN</string>
 | 
			
		||||
	<string-array name="AcceptAllServerCertificates_values">
 | 
			
		||||
		<item>IGNORE</item>
 | 
			
		||||
		<item>WARN</item>
 | 
			
		||||
 
 | 
			
		||||
@@ -1224,6 +1224,9 @@
 | 
			
		||||
  <string name="enable_fingerprint_hint">Keepass2Android has detected biometric hardware. Do you want to enable Biometric Unlock for this database?</string>
 | 
			
		||||
  <string name="post_notifications_dialog_title">Allow notifications</string>
 | 
			
		||||
  <string name="post_notifications_dialog_message">Keepass2Android can show notifications with buttons to copy values like passwords and TOTPs to clipboard, or to bring up the built-in keyboard. This is useful to transfer values into other apps without switching to Keepass2Android repeatedly. Do you want to enable such notifications?</string>
 | 
			
		||||
  <string name="post_notifications_snackbar">Cannot make entry available through notification. No permission granted.</string>
 | 
			
		||||
  <string name="post_notifications_snackbar_config">Configure</string>
 | 
			
		||||
  
 | 
			
		||||
  <string name="post_notifications_dialog_allow">Allow notifications</string>
 | 
			
		||||
  <string name="post_notifications_dialog_disable">Disable this feature</string>
 | 
			
		||||
  <string name="post_notifications_dialog_notnow">Not now</string>
 | 
			
		||||
@@ -1249,9 +1252,5 @@
 | 
			
		||||
  <string name="kp2a_switch_on_sendgodone_summary">Switch back when pressing send/go/done</string>
 | 
			
		||||
  <string name="qr_scanning_error_no_google_play_services">QR code scanning requires Google Play Services. Please install or update Google Play Services on your device.</string>
 | 
			
		||||
<string name="english_ime_settings">Android keyboard settings</string>
 | 
			
		||||
  <string name="autoswitch_enabled_but_not_setup">Note: You have enabled App - Settings - Password access - Keyboard switching - Auto-switch keyboard, but it doesn\'t seem to be configured correctly.</string>
 | 
			
		||||
  <string name="switch_keyboard_for_totp_enabled">Note: You have enabled App - Password access - Autofill-Service - Autofill for TOTP entries. This can cause this window to show when you open an entry with a TOTP.</string>
 | 
			
		||||
  <string name="switch_keyboard_inside_kp2a_enabled">Note: You have enabled App - Security - Use built-in keyboard inside Keepass2Android. This can cause this window to show when you open the app or edit an entry.</string>
 | 
			
		||||
  <string name="switch_keyboard_on_search_enabled">Note: You have enabled App - Security - Password access - Keyboard switching - Switch keyboard. This can cause this window to show when you search for an entry from the browser.</string>
 | 
			
		||||
  
 | 
			
		||||
</resources>
 | 
			
		||||
    
 | 
			
		||||
    </resources>
 | 
			
		||||
@@ -328,6 +328,7 @@ namespace keepass2android
 | 
			
		||||
                    if (prefs.GetBoolean("kp2a_switch_rooted", false))
 | 
			
		||||
                    {
 | 
			
		||||
                        activationCondition = ActivationCondition.Always;
 | 
			
		||||
                        Kp2aLog.Log("Will activate keyboard because SearchUrlTask opened with ActionSend and kp2a_switch_rooted");
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
@@ -336,6 +337,7 @@ namespace keepass2android
 | 
			
		||||
                        if (prefs.GetBoolean(this.GetString(Resource.String.OpenKp2aKeyboardAutomatically_key), this.Resources.GetBoolean(Resource.Boolean.OpenKp2aKeyboardAutomatically_default)))
 | 
			
		||||
                        {
 | 
			
		||||
                            activationCondition = ActivationCondition.Always;
 | 
			
		||||
                            Kp2aLog.Log("Will activate keyboard because SearchUrlTask opened with ActionSend and OpenKp2aKeyboardAutomatically");
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,6 @@ using System.Threading;
 | 
			
		||||
using Android.App;
 | 
			
		||||
using Android.Content;
 | 
			
		||||
using Android.OS;
 | 
			
		||||
using Android.Preferences;
 | 
			
		||||
using Android.Runtime;
 | 
			
		||||
using Android.Util;
 | 
			
		||||
using Android.Views;
 | 
			
		||||
@@ -16,8 +15,8 @@ using keepass2android;
 | 
			
		||||
 | 
			
		||||
namespace keepass2android
 | 
			
		||||
{
 | 
			
		||||
    [Activity(Label = AppNames.AppName, Theme = "@style/Kp2aTheme_BlueActionBar")]
 | 
			
		||||
    public class SwitchImeActivity : AndroidX.AppCompat.App.AppCompatActivity
 | 
			
		||||
    [Activity(Label = AppNames.AppName, TaskAffinity = "", NoHistory = true)]
 | 
			
		||||
    public class SwitchImeActivity : Activity
 | 
			
		||||
    {
 | 
			
		||||
        protected override void OnCreate(Bundle savedInstanceState)
 | 
			
		||||
        {
 | 
			
		||||
@@ -25,26 +24,7 @@ namespace keepass2android
 | 
			
		||||
            SetContentView(Resource.Layout.switch_ime_activity_layout);
 | 
			
		||||
            FindViewById<Button>(Resource.Id.btn_reopen).Click += (sender, args) => TrySwitchKeyboard();
 | 
			
		||||
            FindViewById<Button>(Resource.Id.btn_cancel).Click += (sender, args) => Finish();
 | 
			
		||||
            FindViewById<Button>(Resource.Id.btn_open_settings).Click += (sender, args) => AppSettingsActivity.Launch(this);
 | 
			
		||||
 | 
			
		||||
            var prefs = PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext);
 | 
			
		||||
 | 
			
		||||
            bool useKp2aKeyboardInKp2a = prefs.GetBoolean(GetString(Resource.String.UseKp2aKeyboardInKp2a_key), false);
 | 
			
		||||
            bool kp2a_switch_rooted = prefs.GetBoolean("kp2a_switch_rooted", false);
 | 
			
		||||
            bool AutoFillTotp_prefs_ActivateKeyboard = prefs.GetBoolean("AutoFillTotp_prefs_ActivateKeyboard_key", false);
 | 
			
		||||
            bool OpenKp2aKeyboardAutomatically = prefs.GetBoolean(GetString(Resource.String.OpenKp2aKeyboardAutomatically_key), Resources.GetBoolean(Resource.Boolean.OpenKp2aKeyboardAutomatically_default));
 | 
			
		||||
 | 
			
		||||
            FindViewById(Resource.Id.note_UseKp2aKeyboardInKp2a).Visibility = useKp2aKeyboardInKp2a ? ViewStates.Visible : ViewStates.Gone;
 | 
			
		||||
            FindViewById(Resource.Id.note_kp2a_switch_rooted).Visibility = kp2a_switch_rooted ? ViewStates.Visible : ViewStates.Gone;
 | 
			
		||||
            FindViewById(Resource.Id.note_AutoFillTotp_prefs_ActivateKeyboard).Visibility = AutoFillTotp_prefs_ActivateKeyboard ? ViewStates.Visible : ViewStates.Gone;
 | 
			
		||||
            FindViewById(Resource.Id.note_OpenKp2aKeyboardAutomatically).Visibility = OpenKp2aKeyboardAutomatically ? ViewStates.Visible : ViewStates.Gone;
 | 
			
		||||
 | 
			
		||||
            bool hasNote = useKp2aKeyboardInKp2a || kp2a_switch_rooted || AutoFillTotp_prefs_ActivateKeyboard || OpenKp2aKeyboardAutomatically;
 | 
			
		||||
            ((LinearLayout)FindViewById(Resource.Id.settings_notes_container)).Visibility = hasNote ? ViewStates.Visible : ViewStates.Gone;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        private string Kp2aInputMethodName
 | 
			
		||||
        {
 | 
			
		||||
            get { return PackageName + "/keepass2android.softkeyboard.KP2AKeyboard"; }
 | 
			
		||||
 
 | 
			
		||||
@@ -803,15 +803,13 @@ namespace keepass2android
 | 
			
		||||
                var hasUnsecureDisplay = HasUnsecureDisplay(context);
 | 
			
		||||
                if (hasUnsecureDisplay)
 | 
			
		||||
                {
 | 
			
		||||
                    Kp2aLog.Log("Display is not secure");
 | 
			
		||||
                    var intent = new Intent(context, typeof(NoSecureDisplayActivity));
 | 
			
		||||
                    intent.AddFlags(ActivityFlags.SingleTop | ActivityFlags.ClearTop);
 | 
			
		||||
                    context.StartActivityForResult(intent, 9999);
 | 
			
		||||
                }
 | 
			
		||||
                Kp2aLog.Log("Setting FLAG_SECURE.");
 | 
			
		||||
 | 
			
		||||
                context.Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);
 | 
			
		||||
            }
 | 
			
		||||
            else Kp2aLog.Log("Secure display disabled by user preference.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static bool SecureDisplayConfigured(Activity context)
 | 
			
		||||
 
 | 
			
		||||
@@ -918,16 +918,14 @@ namespace keepass2android
 | 
			
		||||
		{
 | 
			
		||||
			var prefs = PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext);
 | 
			
		||||
 | 
			
		||||
			ValidationMode validationMode = ValidationMode.Error;
 | 
			
		||||
			ValidationMode validationMode = ValidationMode.Warn;
 | 
			
		||||
 | 
			
		||||
			string strValMode = prefs.GetString(LocaleManager.LocalizedAppContext.Resources.GetString(Resource.String.AcceptAllServerCertificates_key),
 | 
			
		||||
												 LocaleManager.LocalizedAppContext.Resources.GetString(Resource.String.AcceptAllServerCertificates_default));
 | 
			
		||||
 | 
			
		||||
			if (strValMode == "IGNORE")
 | 
			
		||||
				validationMode = ValidationMode.Ignore;
 | 
			
		||||
            else if (strValMode == "WARN")
 | 
			
		||||
                validationMode = ValidationMode.Warn;
 | 
			
		||||
            else if (strValMode == "ERROR")
 | 
			
		||||
			else if (strValMode == "ERROR")
 | 
			
		||||
				validationMode = ValidationMode.Error;
 | 
			
		||||
			return validationMode;
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -355,6 +355,10 @@ namespace keepass2android
 | 
			
		||||
                                        activity.GetString(Resource.String
 | 
			
		||||
                                            .OpenKp2aKeyboardAutomaticallyOnlyAfterSearch_key), false);
 | 
			
		||||
 | 
			
		||||
            Kp2aLog.Log($"AppTask.CompleteOnCreateEntryActivity. ActivateKeyboard={activateKeyboard}, kp2a_switch_rooted={prefs.GetBoolean("kp2a_switch_rooted", false)}, OpenKp2aKeyboardAutomaticallyOnlyAfterSearch={prefs.GetBoolean(
 | 
			
		||||
                activity.GetString(Resource.String
 | 
			
		||||
                    .OpenKp2aKeyboardAutomaticallyOnlyAfterSearch_key), false)}");
 | 
			
		||||
 | 
			
		||||
            activity.StartNotificationsService(activateKeyboard);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -622,6 +626,7 @@ namespace keepass2android
 | 
			
		||||
            bool isTotpEntry = totpPluginAdapter != null;
 | 
			
		||||
			
 | 
			
		||||
            bool activateKeyboard = ActivateKeyboard == ActivationCondition.Always || (ActivateKeyboard == ActivationCondition.WhenTotp && isTotpEntry);
 | 
			
		||||
			Kp2aLog.Log($"activateKeyboard == {activateKeyboard}. Task.Activate=={ActivateKeyboard}, isTotpEntry={isTotpEntry}");
 | 
			
		||||
 | 
			
		||||
            if ((ShowUserNotifications == ActivationCondition.Always)
 | 
			
		||||
                || ((ShowUserNotifications == ActivationCondition.WhenTotp) && isTotpEntry)
 | 
			
		||||
 
 | 
			
		||||
@@ -732,12 +732,6 @@
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <AndroidNativeLibrary Include="..\java\argon2\libs\armeabi-v7a\libargon2.so" Link="armeabi-v7a\libargon2.so" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <AndroidNativeLibrary Include="..\java\argon2\libs\x86\libargon2.so" Link="x86\libargon2.so" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <AndroidNativeLibrary Include="..\java\argon2\libs\x86_64\libargon2.so" Link="x86_64\libargon2.so" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.7.0.5" />
 | 
			
		||||
    <PackageReference Include="Xamarin.AndroidX.AppCompat.AppCompatResources" Version="1.7.0.5" />
 | 
			
		||||
 
 | 
			
		||||
@@ -878,6 +878,37 @@ namespace keepass2android
 | 
			
		||||
        {
 | 
			
		||||
            get { return PackageName + "/keepass2android.softkeyboard.KP2AKeyboard"; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static bool IsChannelPermissionGranted(Context context, string channelId)
 | 
			
		||||
        {
 | 
			
		||||
            if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
 | 
			
		||||
            {
 | 
			
		||||
                if (!string.IsNullOrEmpty(channelId))
 | 
			
		||||
                {
 | 
			
		||||
                    NotificationManager? manager =
 | 
			
		||||
                        (NotificationManager?)context.GetSystemService(Context.NotificationService)!;
 | 
			
		||||
                    NotificationChannel? channel = manager?.GetNotificationChannel(channelId);
 | 
			
		||||
                    return channel?.Importance != Android.App.NotificationImportance.None;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static bool HasEntryNotificationPermissions(Context context, bool activateKeyboard)
 | 
			
		||||
        {
 | 
			
		||||
            if (!NotificationManagerCompat.From(context).AreNotificationsEnabled())
 | 
			
		||||
            {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return IsChannelPermissionGranted(context, App.NotificationChannelIdEntry);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [BroadcastReceiver(Permission = "keepass2android." + AppNames.PackagePart + ".permission.CopyToClipboard")]
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user