diff --git a/src/Core/App.xaml.cs b/src/Core/App.xaml.cs
index e550a8989..38709023f 100644
--- a/src/Core/App.xaml.cs
+++ b/src/Core/App.xaml.cs
@@ -69,12 +69,18 @@ namespace Bit.App
CurrentWindow.Page = value;
}
}
- }
+ }
- public static Window CurrentWindow { get; private set; }
-
- private Window _autofillWindow;
- private Window _mainWindow;
+ ///
+ /// Find the Current Active Window. There should only be one at any point in Android
+ ///
+ public static ResumeWindow CurrentWindow
+ {
+ get
+ {
+ return Application.Current.Windows.OfType().FirstOrDefault(w => w.IsActive);
+ }
+ }
//Allows setting Options from MainActivity before base.OnCreate
public void SetOptions(AppOptions appOptions)
@@ -94,64 +100,22 @@ namespace Bit.App
return new Window(new NavigationPage()); //No actual page needed. Only used for auto-filling the fields directly (externally)
}
- //If there's already an existing autofill window we try to get rid of it, mostly to avoid edge cases scenarios.
- if (_autofillWindow != null)
- {
- CloseWindow(_autofillWindow);
- }
-
//"Internal" Autofill and Uri/Otp/CreateSend. This is where we create the autofill specific Window
if (Options != null && (Options.FromAutofillFramework || Options.Uri != null || Options.OtpData != null || Options.CreateSend != null))
{
- _autofillWindow = new Window(new NavigationPage(new AndroidNavigationRedirectPage()));
- _autofillWindow.Created += WindowOnCreatedOrActivated;
- _autofillWindow.Activated += WindowOnCreatedOrActivated;
- _autofillWindow.Stopped += WindowOnStopped;
- _autofillWindow.Destroying += AutofillWindowOnDestroying;
- _isResumed = true;
- return _autofillWindow;
+ _isResumed = true; //Specifically for the Autofill scenario we need to manually set the _isResumed here
+ return new AutoFillWindow(new NavigationPage(new AndroidNavigationRedirectPage()));
}
- //If we don't have an existing main window we create it, otherwise we just reuse the one we had.
- if(_mainWindow == null)
+ //If we have an existing MainAppWindow we can use that one
+ var mainAppWindow = Windows.OfType().FirstOrDefault();
+ if (mainAppWindow != null)
{
- _mainWindow = new Window(new NavigationPage(new HomePage(Options)));
- _mainWindow.Created += WindowOnCreatedOrActivated;
- _mainWindow.Activated += WindowOnCreatedOrActivated;
- _mainWindow.Stopped += WindowOnStopped;
- _mainWindow.Destroying += MainWindowOnDestroying;
+ mainAppWindow.PendingPage = new NavigationPage(new HomePage(Options));
}
- return _mainWindow;
- }
-
- private void MainWindowOnDestroying(object sender, EventArgs e)
- {
- _mainWindow.Created -= WindowOnCreatedOrActivated;
- _mainWindow.Activated -= WindowOnCreatedOrActivated;
- _mainWindow.Stopped -= WindowOnStopped;
- _mainWindow.Destroying -= AutofillWindowOnDestroying;
- }
-
- private void AutofillWindowOnDestroying(object sender, EventArgs e)
- {
- _autofillWindow.Created -= WindowOnCreatedOrActivated;
- _autofillWindow.Activated -= WindowOnCreatedOrActivated;
- _autofillWindow.Stopped -= WindowOnStopped;
- _autofillWindow.Destroying -= AutofillWindowOnDestroying;
- }
-
- private void WindowOnStopped(object sender, EventArgs e)
- {
- CurrentWindow = null;
- }
-
- private void WindowOnCreatedOrActivated(object sender, EventArgs e)
- {
- if (sender is Window window)
- {
- CurrentWindow = window;
- }
+ //Create new main window
+ return new MainAppWindow(new NavigationPage(new HomePage(Options)));
}
#elif IOS
//iOS doesn't use the CreateWindow override used in Android so we just set the Application.Current.MainPage directly
@@ -589,7 +553,7 @@ namespace Bit.App
};
_isResumed = true;
#if IOS
- //We only set the MainPage here for iOS as Android is using the CreateWindow override for the initial page.
+ //We only set the MainPage here for iOS. Android is using the CreateWindow override for the initial page.
App.MainPage = new NavigationPage(new HomePage(Options));
#endif
_accountsManager.NavigateOnAccountChangeAsync().FireAndForget();
diff --git a/src/Core/ResumeWindow.cs b/src/Core/ResumeWindow.cs
new file mode 100644
index 000000000..643b7e98c
--- /dev/null
+++ b/src/Core/ResumeWindow.cs
@@ -0,0 +1,45 @@
+namespace Bit.Core
+{
+ // This ResumeWindow is used as a Workaround for Android to be able to find the current "IsActive" Window
+ // It also allows setting a "PendingPage" on an existing Window which then navigates when the Window is active.
+ public class ResumeWindow : Window
+ {
+ public Page PendingPage {get;set;}
+ public bool IsActive { get; set; }
+
+ public ResumeWindow(Page page) : base(page) { }
+
+ ///
+ /// You need to do this inside OnActivated not OnResumed
+ /// Androids OnResume maps to OnActivated
+ /// Androids OnRestart is what Maps to OnResumed
+ /// I realize this is confusing from the perspective of Android
+ /// https://github.com/dotnet/maui/issues/1720 explains it a bit better
+ ///
+ protected override void OnActivated()
+ {
+ base.OnActivated();
+
+ if (PendingPage is not null)
+ Page = PendingPage;
+
+ PendingPage = null;
+ IsActive = true;
+ }
+
+ protected override void OnDeactivated()
+ {
+ IsActive = false;
+ }
+ }
+
+ public class MainAppWindow : ResumeWindow
+ {
+ public MainAppWindow(Page page) : base(page) { }
+ }
+
+ public class AutoFillWindow : ResumeWindow
+ {
+ public AutoFillWindow(Page page) : base(page){ }
+ }
+}