summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Platform.Android/FormsApplicationActivity.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Platform.Android/FormsApplicationActivity.cs')
-rw-r--r--Xamarin.Forms.Platform.Android/FormsApplicationActivity.cs319
1 files changed, 319 insertions, 0 deletions
diff --git a/Xamarin.Forms.Platform.Android/FormsApplicationActivity.cs b/Xamarin.Forms.Platform.Android/FormsApplicationActivity.cs
new file mode 100644
index 00000000..c05c79f6
--- /dev/null
+++ b/Xamarin.Forms.Platform.Android/FormsApplicationActivity.cs
@@ -0,0 +1,319 @@
+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;
+
+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 = 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);
+
+ _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);
+ }
+
+ 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);
+
+ if (!Forms.SupportsProgress)
+ return;
+
+ SetProgressBarIndeterminate(true);
+ 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());
+ }
+
+ 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)
+ _application.SendSleepAsync().Wait();
+ }
+
+ void SetMainPage()
+ {
+ InternalSetPage(_application.MainPage);
+ }
+
+ void UpdateProgressBarVisibility(bool isBusy)
+ {
+ if (!Forms.SupportsProgress)
+ return;
+ SetProgressBarIndeterminateVisibility(isBusy);
+ }
+
+ internal class DefaultApplication : Application
+ {
+ }
+ }
+} \ No newline at end of file