зеркало из https://github.com/DeGsoft/maui-linux.git
346 строки
10 KiB
C#
346 строки
10 KiB
C#
using System;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using Android.App;
|
|
using Android.Content;
|
|
using Android.Content.Res;
|
|
using Android.OS;
|
|
using Android.Views;
|
|
using Android.Widget;
|
|
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
|
|
|
|
namespace Xamarin.Forms.Platform.Android
|
|
{
|
|
public class FormsApplicationActivity : Activity, IDeviceInfoProvider, IStartActivityForResult
|
|
{
|
|
public delegate bool BackButtonPressedEventHandler(object sender, EventArgs e);
|
|
|
|
readonly ConcurrentDictionary<int, Action<Result, Intent>> _activityResultCallbacks = new ConcurrentDictionary<int, Action<Result, Intent>>();
|
|
|
|
Application _application;
|
|
Platform _canvas;
|
|
AndroidApplicationLifecycleState _currentState;
|
|
LinearLayout _layout;
|
|
|
|
int _nextActivityResultCallbackKey;
|
|
|
|
AndroidApplicationLifecycleState _previousState;
|
|
|
|
protected FormsApplicationActivity()
|
|
{
|
|
_previousState = AndroidApplicationLifecycleState.Uninitialized;
|
|
_currentState = AndroidApplicationLifecycleState.Uninitialized;
|
|
}
|
|
|
|
public event EventHandler ConfigurationChanged;
|
|
|
|
int IStartActivityForResult.RegisterActivityResultCallback(Action<Result, Intent> callback)
|
|
{
|
|
int requestCode = _nextActivityResultCallbackKey;
|
|
|
|
while (!_activityResultCallbacks.TryAdd(requestCode, callback))
|
|
{
|
|
_nextActivityResultCallbackKey += 1;
|
|
requestCode = _nextActivityResultCallbackKey;
|
|
}
|
|
|
|
_nextActivityResultCallbackKey += 1;
|
|
|
|
return requestCode;
|
|
}
|
|
|
|
void IStartActivityForResult.UnregisterActivityResultCallback(int requestCode)
|
|
{
|
|
Action<Result, Intent> callback;
|
|
_activityResultCallbacks.TryRemove(requestCode, out callback);
|
|
}
|
|
|
|
public static event BackButtonPressedEventHandler BackPressed;
|
|
|
|
public override void OnBackPressed()
|
|
{
|
|
if (BackPressed != null && BackPressed(this, EventArgs.Empty))
|
|
return;
|
|
base.OnBackPressed();
|
|
}
|
|
|
|
public override void OnConfigurationChanged(Configuration newConfig)
|
|
{
|
|
base.OnConfigurationChanged(newConfig);
|
|
EventHandler handler = ConfigurationChanged;
|
|
if (handler != null)
|
|
handler(this, new EventArgs());
|
|
}
|
|
|
|
// FIXME: THIS SHOULD NOT BE MANDATORY
|
|
// or
|
|
// This should be specified in an interface and formalized, perhaps even provide a stock AndroidActivity users
|
|
// can derive from to avoid having to do any work.
|
|
public override bool OnOptionsItemSelected(IMenuItem item)
|
|
{
|
|
if (item.ItemId == global::Android.Resource.Id.Home)
|
|
_canvas.SendHomeClicked();
|
|
return base.OnOptionsItemSelected(item);
|
|
}
|
|
|
|
public override bool OnPrepareOptionsMenu(IMenu menu)
|
|
{
|
|
_canvas.PrepareMenu(menu);
|
|
return base.OnPrepareOptionsMenu(menu);
|
|
}
|
|
|
|
[Obsolete("Please use protected LoadApplication (Application app) instead")]
|
|
public void SetPage(Page page)
|
|
{
|
|
var application = new DefaultApplication { MainPage = page };
|
|
LoadApplication(application);
|
|
}
|
|
|
|
protected void LoadApplication(Application application)
|
|
{
|
|
if (application == null)
|
|
throw new ArgumentNullException("application");
|
|
|
|
(application as IApplicationController)?.SetAppIndexingProvider(new AndroidAppIndexProvider(this));
|
|
|
|
_application = application;
|
|
Xamarin.Forms.Application.Current = application;
|
|
|
|
application.PropertyChanged += AppOnPropertyChanged;
|
|
|
|
SetMainPage();
|
|
}
|
|
|
|
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
|
|
{
|
|
base.OnActivityResult(requestCode, resultCode, data);
|
|
|
|
Action<Result, Intent> callback;
|
|
|
|
if (_activityResultCallbacks.TryGetValue(requestCode, out callback))
|
|
callback(resultCode, data);
|
|
}
|
|
|
|
protected override void OnCreate(Bundle savedInstanceState)
|
|
{
|
|
Window.RequestFeature(WindowFeatures.IndeterminateProgress);
|
|
|
|
base.OnCreate(savedInstanceState);
|
|
|
|
SetSoftInputMode();
|
|
|
|
_layout = new LinearLayout(BaseContext);
|
|
SetContentView(_layout);
|
|
|
|
Xamarin.Forms.Application.ClearCurrent();
|
|
|
|
_previousState = _currentState;
|
|
_currentState = AndroidApplicationLifecycleState.OnCreate;
|
|
|
|
OnStateChanged();
|
|
}
|
|
|
|
protected override void OnDestroy()
|
|
{
|
|
// may never be called
|
|
base.OnDestroy();
|
|
|
|
MessagingCenter.Unsubscribe<Page, AlertArguments>(this, Page.AlertSignalName);
|
|
MessagingCenter.Unsubscribe<Page, bool>(this, Page.BusySetSignalName);
|
|
MessagingCenter.Unsubscribe<Page, ActionSheetArguments>(this, Page.ActionSheetSignalName);
|
|
|
|
if (_canvas != null)
|
|
((IDisposable)_canvas).Dispose();
|
|
}
|
|
|
|
protected override void OnPause()
|
|
{
|
|
_layout.HideKeyboard(true);
|
|
|
|
// 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()
|
|
{
|
|
// counterpart to OnPause
|
|
base.OnResume();
|
|
|
|
_previousState = _currentState;
|
|
_currentState = AndroidApplicationLifecycleState.OnResume;
|
|
|
|
OnStateChanged();
|
|
}
|
|
|
|
protected override void OnStart()
|
|
{
|
|
base.OnStart();
|
|
|
|
_previousState = _currentState;
|
|
_currentState = AndroidApplicationLifecycleState.OnStart;
|
|
|
|
OnStateChanged();
|
|
}
|
|
|
|
// Scenarios that stop and restart you 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 recieves 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)
|
|
{
|
|
if (args.PropertyName == "MainPage")
|
|
InternalSetPage(_application.MainPage);
|
|
if (args.PropertyName == PlatformConfiguration.AndroidSpecific.Application.WindowSoftInputModeAdjustProperty.PropertyName)
|
|
SetSoftInputMode();
|
|
}
|
|
|
|
void InternalSetPage(Page page)
|
|
{
|
|
if (!Forms.IsInitialized)
|
|
throw new InvalidOperationException("Call Forms.Init (Activity, Bundle) before this");
|
|
|
|
if (_canvas != null)
|
|
{
|
|
_canvas.SetPage(page);
|
|
return;
|
|
}
|
|
|
|
var busyCount = 0;
|
|
MessagingCenter.Subscribe(this, Page.BusySetSignalName, (Page sender, bool enabled) =>
|
|
{
|
|
busyCount = Math.Max(0, enabled ? busyCount + 1 : busyCount - 1);
|
|
UpdateProgressBarVisibility(busyCount > 0);
|
|
});
|
|
|
|
UpdateProgressBarVisibility(busyCount > 0);
|
|
|
|
MessagingCenter.Subscribe(this, Page.AlertSignalName, (Page sender, AlertArguments arguments) =>
|
|
{
|
|
AlertDialog alert = new AlertDialog.Builder(this).Create();
|
|
alert.SetTitle(arguments.Title);
|
|
alert.SetMessage(arguments.Message);
|
|
if (arguments.Accept != null)
|
|
alert.SetButton((int)DialogButtonType.Positive, arguments.Accept, (o, args) => arguments.SetResult(true));
|
|
alert.SetButton((int)DialogButtonType.Negative, arguments.Cancel, (o, args) => arguments.SetResult(false));
|
|
alert.CancelEvent += (o, args) => { arguments.SetResult(false); };
|
|
alert.Show();
|
|
});
|
|
|
|
MessagingCenter.Subscribe(this, Page.ActionSheetSignalName, (Page sender, ActionSheetArguments arguments) =>
|
|
{
|
|
var builder = new AlertDialog.Builder(this);
|
|
builder.SetTitle(arguments.Title);
|
|
string[] items = arguments.Buttons.ToArray();
|
|
builder.SetItems(items, (sender2, args) => { arguments.Result.TrySetResult(items[args.Which]); });
|
|
|
|
if (arguments.Cancel != null)
|
|
builder.SetPositiveButton(arguments.Cancel, delegate { arguments.Result.TrySetResult(arguments.Cancel); });
|
|
|
|
if (arguments.Destruction != null)
|
|
builder.SetNegativeButton(arguments.Destruction, delegate { arguments.Result.TrySetResult(arguments.Destruction); });
|
|
|
|
AlertDialog dialog = builder.Create();
|
|
builder.Dispose();
|
|
//to match current functionality of renderer we set cancelable on outside
|
|
//and return null
|
|
dialog.SetCanceledOnTouchOutside(true);
|
|
dialog.CancelEvent += (sender3, e) => { arguments.SetResult(null); };
|
|
dialog.Show();
|
|
});
|
|
|
|
_canvas = new Platform(this);
|
|
if (_application != null)
|
|
_application.Platform = _canvas;
|
|
_canvas.SetPage(page);
|
|
_layout.AddView(_canvas.GetViewGroup());
|
|
}
|
|
|
|
async void OnStateChanged()
|
|
{
|
|
if (_application == null)
|
|
return;
|
|
|
|
if (_previousState == AndroidApplicationLifecycleState.OnCreate && _currentState == AndroidApplicationLifecycleState.OnStart)
|
|
_application.SendStart();
|
|
else if (_previousState == AndroidApplicationLifecycleState.OnStop && _currentState == AndroidApplicationLifecycleState.OnRestart)
|
|
_application.SendResume();
|
|
else if (_previousState == AndroidApplicationLifecycleState.OnPause && _currentState == AndroidApplicationLifecycleState.OnStop)
|
|
await _application.SendSleepAsync();
|
|
}
|
|
|
|
void SetMainPage()
|
|
{
|
|
InternalSetPage(_application.MainPage);
|
|
}
|
|
|
|
void SetSoftInputMode()
|
|
{
|
|
SoftInput adjust = SoftInput.AdjustPan;
|
|
|
|
if (Xamarin.Forms.Application.Current != null)
|
|
{
|
|
var elementValue = Xamarin.Forms.Application.Current.OnThisPlatform().GetWindowSoftInputModeAdjust();
|
|
switch (elementValue)
|
|
{
|
|
default:
|
|
case WindowSoftInputModeAdjust.Pan:
|
|
adjust = SoftInput.AdjustPan;
|
|
break;
|
|
case WindowSoftInputModeAdjust.Resize:
|
|
adjust = SoftInput.AdjustResize;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Window.SetSoftInputMode(adjust);
|
|
}
|
|
|
|
void UpdateProgressBarVisibility(bool isBusy)
|
|
{
|
|
if (!Forms.SupportsProgress)
|
|
return;
|
|
#pragma warning disable 612, 618
|
|
SetProgressBarIndeterminate(true);
|
|
SetProgressBarIndeterminateVisibility(isBusy);
|
|
#pragma warning restore 612, 618
|
|
}
|
|
|
|
internal class DefaultApplication : Application
|
|
{
|
|
}
|
|
}
|
|
} |