1
0
mirror of https://github.com/bitwarden/mobile.git synced 2024-11-29 12:45:20 +01:00

[PM-6552] Fix for Android Window issues when opening Autofill/Accessibility (#3051)

* PM-6552 Removed several of the Window Workarounds for Android. Now always relying on the AndroidNavigationRedirectPage.
AndroidNavigationRedirectPage now more resilient to failure and navigates to HomePage as fallback.

* Update src/Core/Pages/AndroidNavigationRedirectPage.xaml.cs

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

---------

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
This commit is contained in:
Dinis Vieira 2024-03-04 13:03:09 +00:00 committed by GitHub
parent bca5b95446
commit 40c80f082d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 26 additions and 74 deletions

View File

@ -46,7 +46,6 @@ namespace Bit.App
// This queue keeps those actions so that when the app has resumed they can still be executed. // This queue keeps those actions so that when the app has resumed they can still be executed.
// Links: https://github.com/dotnet/maui/issues/11501 and https://bitwarden.atlassian.net/wiki/spaces/NMME/pages/664862722/MainPage+Assignments+not+working+on+Android+on+Background+or+App+resume // Links: https://github.com/dotnet/maui/issues/11501 and https://bitwarden.atlassian.net/wiki/spaces/NMME/pages/664862722/MainPage+Assignments+not+working+on+Android+on+Background+or+App+resume
private readonly Queue<Action> _onResumeActions = new Queue<Action>(); private readonly Queue<Action> _onResumeActions = new Queue<Action>();
private bool _hasNavigatedToAutofillWindow;
#if ANDROID #if ANDROID
@ -108,8 +107,6 @@ namespace Bit.App
} }
} }
public bool HasNavigatedToAccessibilitySettings { get; set; }
protected override Window CreateWindow(IActivationState activationState) protected override Window CreateWindow(IActivationState activationState)
{ {
//When executing from AutofillExternalActivity we don't have "Options" so we need to filter "manually" //When executing from AutofillExternalActivity we don't have "Options" so we need to filter "manually"
@ -122,53 +119,8 @@ namespace Bit.App
return new Window(new NavigationPage()); //No actual page needed. Only used for auto-filling the fields directly (externally) return new Window(new NavigationPage()); //No actual page needed. Only used for auto-filling the fields directly (externally)
} }
//"Internal" Autofill and Uri/Otp/CreateSend. This is where we create the autofill specific Window _isResumed = true;
if (Options != null && (Options.FromAutofillFramework || Options.Uri != null || Options.OtpData != null || Options.CreateSend != null)) return new ResumeWindow(new NavigationPage(new AndroidNavigationRedirectPage(Options)));
{
_isResumed = true; //Specifically for the Autofill scenario we need to manually set the _isResumed here
_hasNavigatedToAutofillWindow = true;
return new AutoFillWindow(new NavigationPage(new AndroidNavigationRedirectPage()));
}
var homePage = new HomePage(Options);
// WORKAROUND: If the user autofills with Accessibility Services enabled and goes back to the application then there is currently an issue
// where this method is called again
// thus it goes through here and the user goes to HomePage as we see here.
// So to solve this, the next flag check has been added which then turns on a flag on the home page
// that will trigger a navigation on the accounts manager when it loads; workarounding this behavior and navigating the user
// to the proper page depending on its state.
// WARNING: this doens't navigate the user to where they were but it acts as if the user had changed their account.
if(_hasNavigatedToAutofillWindow)
{
homePage.PerformNavigationOnAccountChangedOnLoad = true;
// this is needed because when coming back from AutofillWindow OnResume won't be called and we need this flag
// so that void Navigate(NavigationTarget navTarget, INavigationParams navParams) doesn't enqueue the navigation
// and it performs it directly.
_isResumed = true;
_hasNavigatedToAutofillWindow = false;
}
// WORKAROUND: This workaround is similar to the one above (_hasNavigatedToAutofillWindow) related with Accessibility Services but this one specifically
// is due to trying to open the Accessibility Settings Page for enabled/disabling
if(HasNavigatedToAccessibilitySettings)
{
homePage.PerformNavigationOnAccountChangedOnLoad = true;
// this is needed because when coming back from AutofillWindow OnResume won't be called and we need this flag
// so that void Navigate(NavigationTarget navTarget, INavigationParams navParams) doesn't enqueue the navigation
// and it performs it directly.
_isResumed = true;
HasNavigatedToAccessibilitySettings = false;
}
//If we have an existing MainAppWindow we can use that one
var mainAppWindow = Windows.OfType<MainAppWindow>().FirstOrDefault();
if (mainAppWindow != null)
{
mainAppWindow.PendingPage = new NavigationPage(homePage);
}
//Create new main window
return new MainAppWindow(new NavigationPage(homePage));
} }
#else #else
//iOS doesn't use the CreateWindow override used in Android so we just set the Application.Current.MainPage directly //iOS doesn't use the CreateWindow override used in Android so we just set the Application.Current.MainPage directly
@ -185,7 +137,7 @@ namespace Bit.App
Application.Current.MainPage = value; Application.Current.MainPage = value;
} }
} }
} }
#endif #endif
public App() : this(null) public App() : this(null)

View File

@ -1,4 +1,6 @@
using Bit.App.Abstractions; using Bit.App.Abstractions;
using Bit.App.Models;
using Bit.App.Pages;
using Bit.Core.Abstractions; using Bit.Core.Abstractions;
using Bit.Core.Utilities; using Bit.Core.Utilities;
@ -6,19 +8,32 @@ namespace Bit.Core.Pages;
public partial class AndroidNavigationRedirectPage : ContentPage public partial class AndroidNavigationRedirectPage : ContentPage
{ {
private readonly IAccountsManager _accountsManager; private AppOptions _options;
private readonly IConditionedAwaiterManager _conditionedAwaiterManager; public AndroidNavigationRedirectPage(AppOptions options)
public AndroidNavigationRedirectPage()
{ {
_accountsManager = ServiceContainer.Resolve<IAccountsManager>("accountsManager"); _options = options ?? new AppOptions();
_conditionedAwaiterManager = ServiceContainer.Resolve<IConditionedAwaiterManager>();
InitializeComponent(); InitializeComponent();
} }
private void AndroidNavigationRedirectPage_OnLoaded(object sender, EventArgs e) private void AndroidNavigationRedirectPage_OnLoaded(object sender, EventArgs e)
{ {
_accountsManager.NavigateOnAccountChangeAsync().FireAndForget(); if (ServiceContainer.TryResolve<IAccountsManager>(out var accountsManager))
_conditionedAwaiterManager.SetAsCompleted(AwaiterPrecondition.AndroidWindowCreated); {
accountsManager.NavigateOnAccountChangeAsync().FireAndForget();
}
else
{
Bit.App.App.MainPage = new NavigationPage(new HomePage(_options)); //Fallback scenario to load HomePage just in case something goes wrong when resolving IAccountsManager
}
if (ServiceContainer.TryResolve<IConditionedAwaiterManager>(out var conditionedAwaiterManager))
{
conditionedAwaiterManager?.SetAsCompleted(AwaiterPrecondition.AndroidWindowCreated);
}
else
{
LoggerHelper.LogEvenIfCantBeResolved(new InvalidOperationException("ConditionedAwaiterManager can't be resolved on Android Navigation redirection"));
}
} }
} }

View File

@ -158,11 +158,6 @@ namespace Bit.App.Pages
await MainThread.InvokeOnMainThreadAsync(() => TriggerPropertyChanged(nameof(UseAccessibility))); await MainThread.InvokeOnMainThreadAsync(() => TriggerPropertyChanged(nameof(UseAccessibility)));
return; return;
} }
#if ANDROID
// WORKAROUND: Set workaround property to avoid an issue when launching the app after being in Accessibility Settings. More Info on App.xaml.cs
((App)Application.Current).HasNavigatedToAccessibilitySettings = true;
#endif
_deviceActionService.OpenAccessibilitySettings(); _deviceActionService.OpenAccessibilitySettings();
} }

View File

@ -32,14 +32,4 @@
IsActive = false; IsActive = false;
} }
} }
public class MainAppWindow : ResumeWindow
{
public MainAppWindow(Page page) : base(page) { }
}
public class AutoFillWindow : ResumeWindow
{
public AutoFillWindow(Page page) : base(page){ }
}
} }