File: Android\AppCompat\FormsAppCompatActivity.cs
Web Access
Project: src\src\Compatibility\Core\src\Compatibility.csproj (Microsoft.Maui.Controls.Compatibility)
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using Android.App;
using Android.Content;
using Android.Content.Res;
using Android.OS;
using Android.Runtime;
using Android.Views;
using AndroidX.AppCompat.App;
using Microsoft.Maui.Controls.Compatibility.Platform.Android.AppCompat;
using Microsoft.Maui.Controls.Internals;
using Microsoft.Maui.Controls.Platform;
using Microsoft.Maui.Controls.PlatformConfiguration.AndroidSpecific;
using Microsoft.Maui.Controls.PlatformConfiguration.AndroidSpecific.AppCompat;
using AColor = Android.Graphics.Color;
using ARelativeLayout = Android.Widget.RelativeLayout;
using AToolbar = AndroidX.AppCompat.Widget.Toolbar;
 
namespace Microsoft.Maui.Controls.Compatibility.Platform.Android
{
	[Flags]
	public enum ActivationFlags : long
	{
		DisableSetStatusBarColor = 1 << 0,
	}
 
#pragma warning disable CA1815 // Override equals and operator equals on value types
	public struct ActivationOptions
#pragma warning restore CA1815 // Override equals and operator equals on value types
	{
		public ActivationOptions(Bundle bundle)
		{
			this = default(ActivationOptions);
			this.Bundle = bundle;
		}
		public Bundle Bundle;
		public ActivationFlags Flags;
	}
 
	[System.Obsolete]
	class FormsAppCompatActivity : AppCompatActivity, IDeviceInfoProvider
	{
		public delegate bool BackButtonPressedEventHandler(object sender, EventArgs e);
 
		Application _application;
 
		AndroidApplicationLifecycleState _currentState;
		ARelativeLayout _layout;
 
		internal Platform Platform { get; private set; }
 
		AndroidApplicationLifecycleState _previousState;
 
		bool _renderersAdded;
		bool _activityCreated;
		bool _needMainPageAssign;
 
		static readonly ManualResetEventSlim PreviousActivityDestroying = new ManualResetEventSlim(true);
 
		// Override this if you want to handle the default Android behavior of restoring fragments on an application restart
		protected virtual bool AllowFragmentRestore => false;
 
		protected FormsAppCompatActivity()
		{
			_previousState = AndroidApplicationLifecycleState.Uninitialized;
			_currentState = AndroidApplicationLifecycleState.Uninitialized;
			PopupManager.Subscribe(this);
		}
 
		public event EventHandler ConfigurationChanged;
 
		[Obsolete]
#pragma warning disable 809
		public override void OnBackPressed()
#pragma warning restore 809
		{
			if (BackPressed != null && BackPressed(this, EventArgs.Empty))
				return;
#pragma warning disable CA1416, CA1422 // Validate platform compatibility
			base.OnBackPressed();
#pragma warning restore CA1416, CA1422 // Validate platform compatibility
		}
 
		public override void OnConfigurationChanged(Configuration newConfig)
		{
			base.OnConfigurationChanged(newConfig);
			ConfigurationChanged?.Invoke(this, new EventArgs());
 
			((IApplication)Microsoft.Maui.Controls.Application.Current)?.ThemeChanged();
		}
 
		public override bool OnOptionsItemSelected(IMenuItem item)
		{
			if (item.ItemId == global::Android.Resource.Id.Home)
				BackPressed?.Invoke(this, EventArgs.Empty);
 
			return base.OnOptionsItemSelected(item);
		}
 
		public void SetStatusBarColor(AColor color)
		{
#pragma warning disable CA1422 // Obsolete in API 35 https://developer.android.com/reference/android/view/Window#setStatusBarColor(int)
			Window.SetStatusBarColor(color);
#pragma warning restore CA1422 // Obsolete in API 35
		}
 
		static void RegisterHandler(Type target, [DynamicallyAccessedMembers(Internals.HandlerType.TargetMembers)] Type handler, Type filter)
		{
			Profile.FrameBegin();
 
			Profile.FramePartition(target.Name);
			Type current = Registrar.Registered.GetHandlerType(target);
 
			if (current == filter)
			{
				Profile.FramePartition("Register");
				Registrar.Registered.Register(target, handler);
			}
 
			Profile.FrameEnd();
		}
 
		// This is currently being used by the previewer please do not change or remove this
		static void RegisterHandlers()
		{
		}
 
		protected void LoadApplication(Application application)
		{
			Profile.FrameBegin();
			if (!_activityCreated)
			{
				throw new InvalidOperationException("Activity OnCreate was not called prior to loading the application. Did you forget a base.OnCreate call?");
			}
 
			if (!_renderersAdded)
			{
				Profile.FramePartition("RegisterHandlers");
				RegisterHandlers();
				_renderersAdded = true;
			}
 
			if (_application != null)
			{
				_application.PropertyChanging -= AppOnPropertyChanging;
				_application.PropertyChanged -= AppOnPropertyChanged;
			}
 
			Profile.FramePartition("SetAppIndexingProvider");
			_application = application ?? throw new ArgumentNullException(nameof(application));
			((IApplicationController)application).SetAppIndexingProvider(new AndroidAppIndexProvider(this));
 
			Profile.FramePartition("SetCurrentApplication");
			Microsoft.Maui.Controls.Application.SetCurrentApplication(application);
 
			Profile.FramePartition("SetSoftInputMode");
			if (Microsoft.Maui.Controls.Application.Current.OnThisPlatform().GetWindowSoftInputModeAdjust() != WindowSoftInputModeAdjust.Unspecified)
				SetSoftInputMode();
 
			Profile.FramePartition("CheckForAppLink");
			CheckForAppLink(Intent);
 
			application.PropertyChanged += AppOnPropertyChanged;
			application.PropertyChanging += AppOnPropertyChanging;
 
			// Wait if old activity destroying is not finished
			PreviousActivityDestroying.Wait();
 
			Profile.FramePartition(nameof(SetMainPage));
 
			SetMainPage();
 
			Profile.FrameEnd();
		}
 
		protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
		{
			base.OnActivityResult(requestCode, resultCode, data);
			ActivityResultCallbackRegistry.InvokeCallback(requestCode, resultCode, data);
		}
 
		protected void OnCreate(ActivationOptions options)
		{
			OnCreate(options.Bundle, options.Flags);
		}
 
		protected override void OnCreate(Bundle savedInstanceState)
		{
			OnCreate(savedInstanceState, default(ActivationFlags));
		}
 
		void OnCreate(
			Bundle savedInstanceState,
			ActivationFlags flags)
		{
			Profile.FrameBegin();
			_activityCreated = true;
			if (!AllowFragmentRestore)
			{
				// Remove the automatically persisted fragment structure; we don't need them
				// because we're rebuilding everything from scratch. This saves a bit of memory
				// and prevents loading errors from child fragment managers
				savedInstanceState?.Remove("android:support:fragments");
			}
 
			Profile.FramePartition("Xamarin.Android.OnCreate");
			base.OnCreate(savedInstanceState);
 
			Profile.FramePartition("SetSupportActionBar");
			AToolbar bar = null;
 
			if (_toolbarResource == 0)
			{
				ToolbarResource = Resource.Layout.toolbar;
			}
 
			if (_tabLayoutResource == 0)
			{
				_tabLayoutResource = Resource.Layout.tabbar;
			}
 
			if (ToolbarResource != 0)
			{
				try
				{
					bar = LayoutInflater.Inflate(ToolbarResource, null).JavaCast<AToolbar>();
				}
				catch (global::Android.Views.InflateException ie)
				{
					throw new InvalidOperationException("ToolbarResource must be set to a androidx.appcompat.widget.Toolbar", ie);
				}
 
				if (bar == null)
					throw new InvalidOperationException("ToolbarResource must be set to a androidx.appcompat.widget.Toolbar");
			}
			else
			{
				bar = new AToolbar(this);
			}
 
			SetSupportActionBar(bar);
 
			Profile.FramePartition("SetContentView");
			_layout = new ARelativeLayout(BaseContext);
			SetContentView(_layout);
 
			Profile.FramePartition("OnStateChanged");
			Microsoft.Maui.Controls.Application.Current = null;
 
			_previousState = _currentState;
			_currentState = AndroidApplicationLifecycleState.OnCreate;
 
			OnStateChanged();
 
			// Allow for the status bar color to be changed
			if ((flags & ActivationFlags.DisableSetStatusBarColor) == 0)
			{
				Profile.FramePartition("Set DrawsSysBarBkgrnds");
				Window.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
			}
 
			Profile.FrameEnd();
		}
 
		protected override void OnDestroy()
		{
			PreviousActivityDestroying.Reset();
 
			if (_application != null)
			{
				_application.PropertyChanging -= AppOnPropertyChanging;
				_application.PropertyChanged -= AppOnPropertyChanged;
			}
 
			PopupManager.Unsubscribe(this);
 
			if (Platform != null)
			{
				_layout.RemoveView(Platform);
				Platform.Dispose();
			}
 
			PreviousActivityDestroying.Set();
 
			// call at the end to avoid race conditions with Platform dispose
			base.OnDestroy();
		}
 
		protected override void OnNewIntent(Intent intent)
		{
			base.OnNewIntent(intent);
			CheckForAppLink(intent);
		}
 
		protected override void OnPause()
		{
			_layout.HideSoftInput();
 
			// Stop animations or other ongoing actions that could consume CPU
			// Commit unsaved changes, build only if users expect such changes to be permanently saved when thy leave such as a draft email
			// Release system resources, such as broadcast receivers, handles to sensors (like GPS), or any resources that may affect battery life when your activity is paused.
			// Avoid writing to permanent storage and CPU intensive tasks
			base.OnPause();
 
			_previousState = _currentState;
			_currentState = AndroidApplicationLifecycleState.OnPause;
 
			OnStateChanged();
		}
 
		protected override void OnRestart()
		{
			base.OnRestart();
 
			_previousState = _currentState;
			_currentState = AndroidApplicationLifecycleState.OnRestart;
 
			OnStateChanged();
		}
 
		protected override void OnResume()
		{
			Profile.FrameBegin();
 
			// counterpart to OnPause
			base.OnResume();
 
			if (_application != null && CurrentFocus != null && _application.OnThisPlatform().GetShouldPreserveKeyboardOnResume())
			{
				CurrentFocus.ShowSoftInput();
			}
 
			_previousState = _currentState;
			_currentState = AndroidApplicationLifecycleState.OnResume;
 
			if (_needMainPageAssign)
			{
				_needMainPageAssign = false;
				SettingMainPage();
				SetMainPage();
			}
 
			OnStateChanged();
 
			Profile.FrameEnd();
		}
 
		protected override void OnStart()
		{
			Profile.FrameBegin();
 
			Profile.FramePartition("Android OnStart");
			base.OnStart();
 
			_previousState = _currentState;
			_currentState = AndroidApplicationLifecycleState.OnStart;
 
			Profile.FramePartition("OnStateChanged");
			OnStateChanged();
 
			Profile.FrameEnd();
		}
 
		// Scenarios that stop and restart your app
		// -- Switches from your app to another app, activity restarts when clicking on the app again.
		// -- Action in your app that starts a new Activity, the current activity is stopped and the second is created, pressing back restarts the activity
		// -- The user receives a phone call while using your app on his or her phone
		protected override void OnStop()
		{
			// writing to storage happens here!
			// full UI obstruction
			// users focus in another activity
			// perform heavy load shutdown operations
			// clean up resources
			// clean up everything that may leak memory
			base.OnStop();
 
			_previousState = _currentState;
			_currentState = AndroidApplicationLifecycleState.OnStop;
 
			OnStateChanged();
		}
 
		void AppOnPropertyChanged(object sender, PropertyChangedEventArgs args)
		{
			// Activity in pause must not react to application changes
			if (_currentState >= AndroidApplicationLifecycleState.OnPause)
			{
				// If the main page is set after the activity has been paused, delay it to resume step
				if (args.PropertyName == nameof(_application.MainPage))
				{
					_needMainPageAssign = true;
				}
 
				return;
			}
 
			if (args.PropertyName == nameof(_application.MainPage))
				SetMainPage();
			if (args.PropertyName == PlatformConfiguration.AndroidSpecific.Application.WindowSoftInputModeAdjustProperty.PropertyName)
				SetSoftInputMode();
		}
 
		void AppOnPropertyChanging(object sender, PropertyChangingEventArgs args)
		{
			// Activity in pause must not react to application changes
			if (_currentState >= AndroidApplicationLifecycleState.OnPause)
			{
				return;
			}
 
			if (args.PropertyName == nameof(_application.MainPage))
			{
				SettingMainPage();
			}
		}
 
		void CheckForAppLink(Intent intent)
		{
			string action = intent.Action;
			string strLink = intent.DataString;
			if (Intent.ActionView != action || string.IsNullOrWhiteSpace(strLink))
				return;
 
			var link = new Uri(strLink);
			_application?.SendOnAppLinkRequestReceived(link);
		}
 
		void InternalSetPage(Page page)
		{
			if (!Forms.IsInitialized)
				throw new InvalidOperationException("Call Forms.Init (Activity, Bundle) before this");
 
			if (Platform != null)
			{
				Platform.SetPage(page);
				return;
			}
 
			PopupManager.ResetBusyCount(this);
 
			Platform = new Platform(this);
			Platform.SetPage(page);
			_layout.AddView(Platform);
			_layout.BringToFront();
		}
 
		void OnStateChanged()
		{
			if (_application == null)
				return;
 
			if (_previousState == AndroidApplicationLifecycleState.OnCreate && _currentState == AndroidApplicationLifecycleState.OnStart)
				_application.SendStart();
			else if (_previousState == AndroidApplicationLifecycleState.OnRestart && _currentState == AndroidApplicationLifecycleState.OnStart)
				_application.SendResume();
			else if (_previousState == AndroidApplicationLifecycleState.OnPause && _currentState == AndroidApplicationLifecycleState.OnStop)
				_application.SendSleep();
		}
 
		// This is currently being used by the previewer please do not change or remove this
		void RegisterHandlerForDefaultRenderer(Type target, [DynamicallyAccessedMembers(Internals.HandlerType.TargetMembers)] Type handler, Type filter)
		{
			RegisterHandler(target, handler, filter);
		}
 
		void SetMainPage()
		{
			InternalSetPage(_application.MainPage);
		}
 
		void SettingMainPage()
		{
			Platform.SettingNewPage();
		}
 
		[PortHandler]
		void SetSoftInputMode()
		{
			var adjust = SoftInput.AdjustPan;
 
			if (Microsoft.Maui.Controls.Application.Current != null)
			{
				WindowSoftInputModeAdjust elementValue = Microsoft.Maui.Controls.Application.Current.OnThisPlatform().GetWindowSoftInputModeAdjust();
				switch (elementValue)
				{
					case WindowSoftInputModeAdjust.Resize:
						adjust = SoftInput.AdjustResize;
						break;
					case WindowSoftInputModeAdjust.Unspecified:
						adjust = SoftInput.AdjustUnspecified;
						break;
					default:
						adjust = SoftInput.AdjustPan;
						break;
				}
			}
 
			Window.SetSoftInputMode(adjust);
		}
 
		internal class DefaultApplication : Application
		{
		}
 
		#region Statics
 
		public static event BackButtonPressedEventHandler BackPressed;
 
		static int _tabLayoutResource;
		public static int TabLayoutResource
		{
			get
			{
				if (_tabLayoutResource == 0)
					return Resource.Layout.tabbar;
 
				return _tabLayoutResource;
			}
			set => _tabLayoutResource = value;
		}
 
		static int _toolbarResource;
		public static int ToolbarResource
		{
			get
			{
				if (_toolbarResource == 0)
					return Resource.Layout.toolbar;
 
				return _toolbarResource;
			}
			set => _toolbarResource = value;
		}
 
		#endregion
	}
}