mirror of
https://github.com/bitwarden/mobile
synced 2025-12-13 06:43:17 +00:00
PM-3349 Added base structure for avoiding Android Autofill crash. This workaround works but it's not complete as it can't handle the entire workflow when showing CipherSelectionPAge (like checking if it should show LockPage)
This commit is contained in:
@@ -74,6 +74,10 @@ namespace Bit.Droid
|
|||||||
// this needs to be called here before base.OnCreate(...)
|
// this needs to be called here before base.OnCreate(...)
|
||||||
Intent?.Validate();
|
Intent?.Validate();
|
||||||
|
|
||||||
|
//We need to get and set the Options before calling OnCreate as that will "trigger" CreateWindow on App.xaml.cs
|
||||||
|
_appOptions = GetOptions();
|
||||||
|
((Bit.App.App)Microsoft.Maui.Controls.Application.Current).SetOptions(_appOptions);
|
||||||
|
|
||||||
base.OnCreate(savedInstanceState);
|
base.OnCreate(savedInstanceState);
|
||||||
|
|
||||||
_deviceActionService.SetScreenCaptureAllowedAsync().FireAndForget(_ =>
|
_deviceActionService.SetScreenCaptureAllowedAsync().FireAndForget(_ =>
|
||||||
@@ -89,7 +93,6 @@ namespace Bit.Droid
|
|||||||
toplayout.FilterTouchesWhenObscured = true;
|
toplayout.FilterTouchesWhenObscured = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_appOptions = GetOptions();
|
|
||||||
CreateNotificationChannel();
|
CreateNotificationChannel();
|
||||||
DisableAndroidFontScale();
|
DisableAndroidFontScale();
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,85 @@ namespace Bit.App
|
|||||||
// 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>();
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ** Workaround for our Android crashes when trying to use Autofill **
|
||||||
|
*
|
||||||
|
* This workaround works by managing the "Window Creation" ourselves. When we get an Autofill initialization we should create a new window instead of reusing the "Main/Current Window".
|
||||||
|
* While this workaround works, it's hard to execute the "workflow" that devices where we should navigate to. Below are some of the things we tried:
|
||||||
|
* 1 - Tried creating "new Window(new NavigationPage)" and invoking the code for handling the Navigations afterward. Issue with this is that the code that handles the navigations doesn't know which "Window" to use and calls the default "Window.Page"
|
||||||
|
* 2 - Tried using CustomWindow implementations to track the "WindowCreated" event and to be able to distinguish the different Window types (Default Window or Window for Autofill for example).
|
||||||
|
* This solution had a bit of overhear work and still required the app to set something line "new Window(new NavigationPage)" before actually knowing where we wanted to navigate to.
|
||||||
|
*
|
||||||
|
* Ideally we could figure out the Navigation we want to do before CreateWindow (on MainActivity.OnCreate) for example. But this needs to be done in async anyway we can't do async in both CreateWindow and MainActivity.OnCreate
|
||||||
|
*/
|
||||||
|
|
||||||
|
public new static Page MainPage
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return CurrentWindow?.Page;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (CurrentWindow != null)
|
||||||
|
{
|
||||||
|
CurrentWindow.Page = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Window CurrentWindow { get; private set; }
|
||||||
|
|
||||||
|
public void SetOptions(AppOptions appOptions)
|
||||||
|
{
|
||||||
|
Options = appOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Window CreateWindow(IActivationState activationState)
|
||||||
|
{
|
||||||
|
if (activationState != null
|
||||||
|
&& activationState.State.TryGetValue("autofillFramework", out string autofillFramework)
|
||||||
|
&& autofillFramework == "true") //TODO: There are likely better ways to filter this. Maybe using Options.
|
||||||
|
{
|
||||||
|
if (activationState.State.ContainsKey("autofillFrameworkCipherId")) //TODO: There are likely better ways to filter this. Maybe using Options.
|
||||||
|
{
|
||||||
|
return new Window(new NavigationPage()); //No actual page needed. Only used for auto-filling the fields directly (externally)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//TODO: IMPORTANT Question: this works if we want to show the CipherSelection, but we are skipping all our ASYNC Navigation workflows where we (for example) check if the user is logged in and/or needs to enter auth again.
|
||||||
|
var autofillWindow = new Window(new NavigationPage(new CipherSelectionPage(Options)));
|
||||||
|
return autofillWindow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(CurrentWindow != null)
|
||||||
|
{
|
||||||
|
//TODO: This likely crashes if we try to have two apps side-by-side on Android
|
||||||
|
//TODO: Question: In these scenarios should a new Window be created or can the same one be reused?
|
||||||
|
return CurrentWindow;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CurrentWindow = new Window(new NavigationPage(new HomePage(Options)));
|
||||||
|
return CurrentWindow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif IOS
|
||||||
|
public new static Page MainPage
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Application.Current.MainPage;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Application.Current.MainPage = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
public App() : this(null)
|
public App() : this(null)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -432,11 +511,11 @@ namespace Bit.App
|
|||||||
Options.Uri = null;
|
Options.Uri = null;
|
||||||
if (isLocked)
|
if (isLocked)
|
||||||
{
|
{
|
||||||
MainPage = new NavigationPage(new LockPage());
|
App.MainPage = new NavigationPage(new LockPage());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MainPage = new TabsPage();
|
App.MainPage = new TabsPage();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -463,7 +542,6 @@ namespace Bit.App
|
|||||||
{
|
{
|
||||||
UpdateThemeAsync();
|
UpdateThemeAsync();
|
||||||
};
|
};
|
||||||
MainPage = new NavigationPage(new HomePage(Options));
|
|
||||||
_accountsManager.NavigateOnAccountChangeAsync().FireAndForget();
|
_accountsManager.NavigateOnAccountChangeAsync().FireAndForget();
|
||||||
ServiceContainer.Resolve<MobilePlatformUtilsService>("platformUtilsService").Init();
|
ServiceContainer.Resolve<MobilePlatformUtilsService>("platformUtilsService").Init();
|
||||||
}
|
}
|
||||||
@@ -535,36 +613,36 @@ namespace Bit.App
|
|||||||
switch (navTarget)
|
switch (navTarget)
|
||||||
{
|
{
|
||||||
case NavigationTarget.HomeLogin:
|
case NavigationTarget.HomeLogin:
|
||||||
MainPage = new NavigationPage(new HomePage(Options));
|
App.MainPage = new NavigationPage(new HomePage(Options));
|
||||||
break;
|
break;
|
||||||
case NavigationTarget.Login:
|
case NavigationTarget.Login:
|
||||||
if (navParams is LoginNavigationParams loginParams)
|
if (navParams is LoginNavigationParams loginParams)
|
||||||
{
|
{
|
||||||
MainPage = new NavigationPage(new LoginPage(loginParams.Email, Options));
|
App.MainPage = new NavigationPage(new LoginPage(loginParams.Email, Options));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NavigationTarget.Lock:
|
case NavigationTarget.Lock:
|
||||||
if (navParams is LockNavigationParams lockParams)
|
if (navParams is LockNavigationParams lockParams)
|
||||||
{
|
{
|
||||||
MainPage = new NavigationPage(new LockPage(Options, lockParams.AutoPromptBiometric));
|
App.MainPage = new NavigationPage(new LockPage(Options, lockParams.AutoPromptBiometric));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MainPage = new NavigationPage(new LockPage(Options));
|
App.MainPage = new NavigationPage(new LockPage(Options));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NavigationTarget.Home:
|
case NavigationTarget.Home:
|
||||||
MainPage = new TabsPage(Options);
|
App.MainPage = new TabsPage(Options);
|
||||||
break;
|
break;
|
||||||
case NavigationTarget.AddEditCipher:
|
case NavigationTarget.AddEditCipher:
|
||||||
MainPage = new NavigationPage(new CipherAddEditPage(appOptions: Options));
|
App.MainPage = new NavigationPage(new CipherAddEditPage(appOptions: Options));
|
||||||
break;
|
break;
|
||||||
case NavigationTarget.AutofillCiphers:
|
case NavigationTarget.AutofillCiphers:
|
||||||
case NavigationTarget.OtpCipherSelection:
|
case NavigationTarget.OtpCipherSelection:
|
||||||
MainPage = new NavigationPage(new CipherSelectionPage(Options));
|
App.MainPage = new NavigationPage(new CipherSelectionPage(Options));
|
||||||
break;
|
break;
|
||||||
case NavigationTarget.SendAddEdit:
|
case NavigationTarget.SendAddEdit:
|
||||||
MainPage = new NavigationPage(new SendAddEditPage(Options));
|
App.MainPage = new NavigationPage(new SendAddEditPage(Options));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
var previousPage = await AppHelpers.ClearPreviousPage();
|
var previousPage = await AppHelpers.ClearPreviousPage();
|
||||||
|
|
||||||
Application.Current.MainPage = new TabsPage(_appOptions, previousPage);
|
App.MainPage = new TabsPage(_appOptions, previousPage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ namespace Bit.App.Pages
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var previousPage = await AppHelpers.ClearPreviousPage();
|
var previousPage = await AppHelpers.ClearPreviousPage();
|
||||||
Application.Current.MainPage = new TabsPage(_appOptions, previousPage);
|
App.MainPage = new TabsPage(_appOptions, previousPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task StartLogInWithMasterPasswordAsync()
|
private async Task StartLogInWithMasterPasswordAsync()
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ namespace Bit.App.Pages
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var previousPage = await AppHelpers.ClearPreviousPage();
|
var previousPage = await AppHelpers.ClearPreviousPage();
|
||||||
Application.Current.MainPage = new TabsPage(_appOptions, previousPage);
|
App.MainPage = new TabsPage(_appOptions, previousPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateTempPasswordAsync()
|
private async Task UpdateTempPasswordAsync()
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ namespace Bit.App.Pages
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var previousPage = await AppHelpers.ClearPreviousPage();
|
var previousPage = await AppHelpers.ClearPreviousPage();
|
||||||
Application.Current.MainPage = new TabsPage(_appOptions, previousPage);
|
App.MainPage = new TabsPage(_appOptions, previousPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateTempPasswordAsync()
|
private async Task UpdateTempPasswordAsync()
|
||||||
|
|||||||
@@ -120,11 +120,11 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
if (await _vaultTimeoutService.IsLockedAsync())
|
if (await _vaultTimeoutService.IsLockedAsync())
|
||||||
{
|
{
|
||||||
Application.Current.MainPage = new NavigationPage(new LockPage(_appOptions));
|
App.MainPage = new NavigationPage(new LockPage(_appOptions));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Application.Current.MainPage = new TabsPage(_appOptions, null);
|
App.MainPage = new TabsPage(_appOptions, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ namespace Bit.App.Pages
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var previousPage = await AppHelpers.ClearPreviousPage();
|
var previousPage = await AppHelpers.ClearPreviousPage();
|
||||||
Application.Current.MainPage = new TabsPage(_appOptions, previousPage);
|
App.MainPage = new TabsPage(_appOptions, previousPage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
private void TwoFactorAuthSuccessWithSSOLocked()
|
private void TwoFactorAuthSuccessWithSSOLocked()
|
||||||
{
|
{
|
||||||
Application.Current.MainPage = new NavigationPage(new LockPage(_appOptions));
|
App.MainPage = new NavigationPage(new LockPage(_appOptions));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task TwoFactorAuthSuccessToMainAsync()
|
private async Task TwoFactorAuthSuccessToMainAsync()
|
||||||
@@ -202,7 +202,7 @@ namespace Bit.App.Pages
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var previousPage = await AppHelpers.ClearPreviousPage();
|
var previousPage = await AppHelpers.ClearPreviousPage();
|
||||||
Application.Current.MainPage = new TabsPage(_appOptions, previousPage);
|
App.MainPage = new TabsPage(_appOptions, previousPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Token_TextChanged(object sender, TextChangedEventArgs e)
|
private void Token_TextChanged(object sender, TextChangedEventArgs e)
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
if (FromAutofillFramework)
|
if (FromAutofillFramework)
|
||||||
{
|
{
|
||||||
Microsoft.Maui.Controls.Application.Current.MainPage = new TabsPage();
|
App.MainPage = new TabsPage();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return base.OnBackButtonPressed();
|
return base.OnBackButtonPressed();
|
||||||
|
|||||||
@@ -430,19 +430,19 @@ namespace Bit.App.Utilities
|
|||||||
{
|
{
|
||||||
if (appOptions.FromAutofillFramework && appOptions.SaveType.HasValue)
|
if (appOptions.FromAutofillFramework && appOptions.SaveType.HasValue)
|
||||||
{
|
{
|
||||||
Application.Current.MainPage = new NavigationPage(new CipherAddEditPage(appOptions: appOptions));
|
App.MainPage = new NavigationPage(new CipherAddEditPage(appOptions: appOptions));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (appOptions.Uri != null
|
if (appOptions.Uri != null
|
||||||
||
|
||
|
||||||
appOptions.OtpData != null)
|
appOptions.OtpData != null)
|
||||||
{
|
{
|
||||||
Application.Current.MainPage = new NavigationPage(new CipherSelectionPage(appOptions));
|
App.MainPage = new NavigationPage(new CipherSelectionPage(appOptions));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (appOptions.CreateSend != null)
|
if (appOptions.CreateSend != null)
|
||||||
{
|
{
|
||||||
Application.Current.MainPage = new NavigationPage(new SendAddEditPage(appOptions));
|
App.MainPage = new NavigationPage(new SendAddEditPage(appOptions));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ namespace Bit.iOS.Core.Services
|
|||||||
{
|
{
|
||||||
if (Application.Current is App.App app && app.Options != null && !app.Options.IosExtension)
|
if (Application.Current is App.App app && app.Options != null && !app.Options.IosExtension)
|
||||||
{
|
{
|
||||||
return app.MainPage.DisplayActionSheet(title, cancel, destruction, buttons);
|
return Bit.App.App.MainPage.DisplayActionSheet(title, cancel, destruction, buttons);
|
||||||
}
|
}
|
||||||
var vc = GetPresentedViewController();
|
var vc = GetPresentedViewController();
|
||||||
if (vc is null)
|
if (vc is null)
|
||||||
|
|||||||
Reference in New Issue
Block a user