Ejemplo n.º 1
0
        public AutoSuspendAppDelegate()
        {
            var host = new SuspensionHost();

            host.IsLaunchingNew = Observable.Never <Unit>();
            host.IsResuming     = _finishedLaunching.Select(_ => Unit.Default);
            host.IsUnpausing    = _activated.Select(_ => Unit.Default);

            var untimelyDeath = new Subject <Unit>();

            AppDomain.CurrentDomain.UnhandledException += (o, e) => untimelyDeath.OnNext(Unit.Default);

            host.ShouldInvalidateState = untimelyDeath;
            host.ShouldPersistState    = _willTerminate.Merge(_backgrounded).SelectMany(app => {
                var taskId = app.BeginBackgroundTask(new NSAction(() => untimelyDeath.OnNext(Unit.Default)));

                // NB: We're being force-killed, signal invalidate instead
                if (taskId == UIApplication.BackgroundTaskInvalid)
                {
                    untimelyDeath.OnNext(Unit.Default);
                    return(Observable.Empty <IDisposable>());
                }

                return(Observable.Return(
                           Disposable.Create(() => app.EndBackgroundTask(taskId))));
            });

            SuspensionHost = host;
        }
        protected AutoSuspendApplication()
        {
            var host = new SuspensionHost();

            var launchNew = new[] { ApplicationExecutionState.ClosedByUser, ApplicationExecutionState.NotRunning, };
            host.IsLaunchingNew = _launched
                .Where(x => launchNew.Contains(x.PreviousExecutionState))
                .Select(_ => Unit.Default);

            host.IsResuming = _launched
                .Where(x => x.PreviousExecutionState == ApplicationExecutionState.Terminated)
                .Select(_ => Unit.Default);

            var unpausing = new[] { ApplicationExecutionState.Suspended, ApplicationExecutionState.Running, };
            host.IsUnpausing = _launched
                .Where(x => unpausing.Contains(x.PreviousExecutionState))
                .Select(_ => Unit.Default);

            var shouldPersistState = new Subject<SuspendingEventArgs>();
            Suspending += (o, e) => shouldPersistState.OnNext(e);
            host.ShouldPersistState =
                shouldPersistState.Select(x => {
                    var deferral = x.SuspendingOperation.GetDeferral();
                    return Disposable.Create(deferral.Complete);
                });

            var shouldInvalidateState = new Subject<Unit>();
            UnhandledException += (o, e) => shouldInvalidateState.OnNext(Unit.Default);
            host.ShouldInvalidateState = shouldInvalidateState;

            SuspensionHost = host;
        }
Ejemplo n.º 3
0
        public AutoSuspendAppDelegate()
        {
            var host = new SuspensionHost();
            host.IsLaunchingNew = Observable.Never<Unit>();
            host.IsResuming = _finishedLaunching.Select(_ => Unit.Default);
            host.IsUnpausing = _activated.Select(_ => Unit.Default);

            var untimelyDeath = new Subject<Unit>();
            AppDomain.CurrentDomain.UnhandledException += (o,e) => untimelyDeath.OnNext(Unit.Default);

            host.ShouldInvalidateState = untimelyDeath;
            host.ShouldPersistState = _willTerminate.Merge(_backgrounded).SelectMany(app => {
                var taskId = app.BeginBackgroundTask(new NSAction(() => untimelyDeath.OnNext(Unit.Default)));

                // NB: We're being force-killed, signal invalidate instead
                if (taskId == UIApplication.BackgroundTaskInvalid) {
                    untimelyDeath.OnNext(Unit.Default);
                    return Observable.Empty<IDisposable>();
                }

                return Observable.Return(
                    Disposable.Create(() => app.EndBackgroundTask(taskId)));
            });

            SuspensionHost = host;
        }
        public AutoSuspendActivityHelper(Activity hostActivity)
        {
            var methodsToCheck = new[] {
                "OnCreate", "OnResume", "OnPause", "OnSaveInstanceState",
            };

            var missingMethod = methodsToCheck
                                .Select(x => {
                var methods = hostActivity.GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
                return(Tuple.Create(x, methods.FirstOrDefault(y => y.Name == x)));
            })
                                .FirstOrDefault(x => x.Item2 == null);

            if (missingMethod != null)
            {
                throw new Exception(String.Format("Your activity must implement {0} and call AutoSuspendActivityHelper.{0}", missingMethod.Item1));
            }

            Observable.Merge(onCreate, onSaveInstanceState)
            .Subscribe(x => AndroidSuspensionHost.latestBundle = x);

            var host = new SuspensionHost();

            host.IsLaunchingNew = onCreate.Select(_ => Unit.Default);
            host.IsResuming     = onResume;
            host.IsUnpausing    = onResume;

            bool hasRecentlyCrashed = false;

            host.SetupDefaultSuspendResumeFunc = new Action <ISuspensionDriver>(driver => {
                driver = driver ?? RxApp.DependencyResolver.GetService <ISuspensionDriver>();

                // TODO: Handle crashes here

                host.ShouldInvalidateState
                .SelectMany(_ => driver.InvalidateState())
                .LoggedCatch(this, Observable.Return(Unit.Default), "Tried to invalidate app state")
                .Subscribe(_ => this.Log().Info("Invalidated app state"));

                host.ShouldPersistState
                .SelectMany(x => driver.SaveState(RootState.Current.ViewModel).Finally(x.Dispose))
                .LoggedCatch(this, Observable.Return(Unit.Default), "Tried to persist app state")
                .Subscribe(_ => this.Log().Info("Persisted application state"));

                host.IsResuming
                .SelectMany(x => driver.LoadState <IApplicationRootState>())
                .LoggedCatch(this,
                             Observable.Defer(() => Observable.Return(RxApp.DependencyResolver.GetService <IApplicationRootState>())),
                             "Failed to restore app state from storage, creating from scratch")
                .ObserveOn(RxApp.MainThreadScheduler)
                .Subscribe(x => RootState.Current.ViewModel = x);

                host.IsLaunchingNew.Subscribe(_ => {
                    RootState.Current.ViewModel = RxApp.DependencyResolver.GetService <IApplicationRootState>();
                });
            });

            SuspensionHost = host;
            AndroidSuspensionHost.inner = host;
        }
        protected AutoSuspendApplication()
        {
            var host = new SuspensionHost();

            host.IsLaunchingNew =
                Observable.FromEventPattern<LaunchingEventArgs>(
                    x => PhoneApplicationService.Current.Launching += x, x => PhoneApplicationService.Current.Launching -= x)
                    .Select(_ => Unit.Default);

            host.IsUnpausing =
                Observable.FromEventPattern<ActivatedEventArgs>(
                    x => PhoneApplicationService.Current.Activated += x, x => PhoneApplicationService.Current.Activated -= x)
                    .Where(x => x.EventArgs.IsApplicationInstancePreserved)
                    .Select(_ => Unit.Default);

            // NB: "Applications should not perform resource-intensive tasks
            // such as loading from isolated storage or a network resource
            // during the Activated event handler because it increase the time
            // it takes for the application to resume"
            host.IsResuming =
                Observable.FromEventPattern<ActivatedEventArgs>(
                    x => PhoneApplicationService.Current.Activated += x, x => PhoneApplicationService.Current.Activated -= x)
                    .Where(x => !x.EventArgs.IsApplicationInstancePreserved)
                    .Select(_ => Unit.Default)
                    .ObserveOn(RxApp.TaskpoolScheduler);

            // NB: No way to tell OS that we need time to suspend, we have to
            // do it in-process
            host.ShouldPersistState = Observable.Merge(
                Observable.FromEventPattern<DeactivatedEventArgs>(
                    x => PhoneApplicationService.Current.Deactivated += x, x => PhoneApplicationService.Current.Deactivated -= x)
                    .Select(_ => Disposable.Empty),
                Observable.FromEventPattern<ClosingEventArgs>(
                    x => PhoneApplicationService.Current.Closing += x, x => PhoneApplicationService.Current.Closing -= x)
                    .Select(_ => Disposable.Empty));

            host.ShouldInvalidateState =
                Observable.FromEventPattern<ApplicationUnhandledExceptionEventArgs>(x => UnhandledException += x, x => UnhandledException -= x)
                    .Select(_ => Unit.Default);

            SuspensionHost = host;
        }
Ejemplo n.º 6
0
        protected AutoSuspendApplication()
        {
            var host = new SuspensionHost();

            var launchNew = new[] { ApplicationExecutionState.ClosedByUser, ApplicationExecutionState.NotRunning, };

            host.IsLaunchingNew = _launched
                                  .Where(x => launchNew.Contains(x.PreviousExecutionState))
                                  .Select(_ => Unit.Default);

            host.IsResuming = _launched
                              .Where(x => x.PreviousExecutionState == ApplicationExecutionState.Terminated)
                              .Select(_ => Unit.Default);

            var unpausing = new[] { ApplicationExecutionState.Suspended, ApplicationExecutionState.Running, };

            host.IsUnpausing = _launched
                               .Where(x => unpausing.Contains(x.PreviousExecutionState))
                               .Select(_ => Unit.Default);

            var shouldPersistState = new Subject <SuspendingEventArgs>();

            Suspending += (o, e) => shouldPersistState.OnNext(e);
            host.ShouldPersistState =
                shouldPersistState.Select(x => {
                var deferral = x.SuspendingOperation.GetDeferral();
                return(Disposable.Create(deferral.Complete));
            });

            var shouldInvalidateState = new Subject <Unit>();

            UnhandledException        += (o, e) => shouldInvalidateState.OnNext(Unit.Default);
            host.ShouldInvalidateState = shouldInvalidateState;

            SuspensionHost = host;
        }
        protected AutoSuspendApplication()
        {
            var host = new SuspensionHost();

            host.IsLaunchingNew =
                Observable.FromEventPattern <LaunchingEventArgs>(
                    x => PhoneApplicationService.Current.Launching += x, x => PhoneApplicationService.Current.Launching -= x)
                .Select(_ => Unit.Default);

            host.IsUnpausing =
                Observable.FromEventPattern <ActivatedEventArgs>(
                    x => PhoneApplicationService.Current.Activated += x, x => PhoneApplicationService.Current.Activated -= x)
                .Where(x => x.EventArgs.IsApplicationInstancePreserved)
                .Select(_ => Unit.Default);

            // NB: "Applications should not perform resource-intensive tasks
            // such as loading from isolated storage or a network resource
            // during the Activated event handler because it increase the time
            // it takes for the application to resume"
            host.IsResuming =
                Observable.FromEventPattern <ActivatedEventArgs>(
                    x => PhoneApplicationService.Current.Activated += x, x => PhoneApplicationService.Current.Activated -= x)
                .Where(x => !x.EventArgs.IsApplicationInstancePreserved)
                .Select(_ => Unit.Default)
                .ObserveOn(RxApp.TaskpoolScheduler);

            // NB: No way to tell OS that we need time to suspend, we have to
            // do it in-process
            host.ShouldPersistState = Observable.Merge(
                Observable.FromEventPattern <DeactivatedEventArgs>(
                    x => PhoneApplicationService.Current.Deactivated += x, x => PhoneApplicationService.Current.Deactivated -= x)
                .Select(_ => Disposable.Empty),
                Observable.FromEventPattern <ClosingEventArgs>(
                    x => PhoneApplicationService.Current.Closing += x, x => PhoneApplicationService.Current.Closing -= x)
                .Select(_ => Disposable.Empty));

            host.ShouldInvalidateState =
                Observable.FromEventPattern <ApplicationUnhandledExceptionEventArgs>(x => UnhandledException += x, x => UnhandledException -= x)
                .Select(_ => Unit.Default);

            SuspensionHost = host;

            //
            // Do the equivalent steps that the boilerplate code does for WP8 apps
            //

            if (RootFrame != null)
            {
                return;
            }
            RootFrame = new PhoneApplicationFrame();

            var currentBackHook = default(IDisposable);
            var currentViewFor  = default(WeakReference <IViewFor>);

            RootFrame.Navigated += (o, e) => {
                // Always clear the WP8 Back Stack, we're using our own
                while (RootFrame.RemoveBackEntry() != null)
                {
                }

                if (currentBackHook != null)
                {
                    currentBackHook.Dispose();
                }
                var page = RootFrame.Content as PhoneApplicationPage;
                if (page != null)
                {
                    currentBackHook = Observable.FromEventPattern <CancelEventArgs>(x => page.BackKeyPress += x, x => page.BackKeyPress -= x)
                                      .Where(_ => ViewModel != null)
                                      .Subscribe(x => {
                        if (!ViewModel.Router.NavigateBack.CanExecute(null))
                        {
                            return;
                        }

                        x.EventArgs.Cancel = true;
                        ViewModel.Router.NavigateBack.Execute(null);
                    });

                    var viewFor = page as IViewFor;
                    if (viewFor == null)
                    {
                        throw new Exception("Your Main Page (i.e. the one that is pointed to by WMAppManifest) must implement IViewFor<YourAppBootstrapperClass>");
                    }

                    currentViewFor    = new WeakReference <IViewFor>(viewFor);
                    viewFor.ViewModel = ViewModel;
                }

                // Finally make it live
                RootVisual = RootFrame;
            };

            _viewModelChanged.StartWith(ViewModel).Where(x => x != null).Subscribe(vm => {
                var viewFor = default(IViewFor);
                if (currentViewFor != null && currentViewFor.TryGetTarget(out viewFor))
                {
                    viewFor.ViewModel = vm;
                }
            });

            UnhandledException += (o, e) => {
                if (Debugger.IsAttached)
                {
                    Debugger.Break();
                }
            };

            RootFrame.NavigationFailed += (o, e) => {
                if (Debugger.IsAttached)
                {
                    Debugger.Break();
                }
            };
        }
Ejemplo n.º 8
0
        protected AutoSuspendApplication()
        {
            var host = new SuspensionHost();

            host.IsLaunchingNew =
                Observable.FromEventPattern<LaunchingEventArgs>(
                    x => PhoneApplicationService.Current.Launching += x, x => PhoneApplicationService.Current.Launching -= x)
                    .Select(_ => Unit.Default);

            host.IsUnpausing =
                Observable.FromEventPattern<ActivatedEventArgs>(
                    x => PhoneApplicationService.Current.Activated += x, x => PhoneApplicationService.Current.Activated -= x)
                    .Where(x => x.EventArgs.IsApplicationInstancePreserved)
                    .Select(_ => Unit.Default);

            // NB: "Applications should not perform resource-intensive tasks 
            // such as loading from isolated storage or a network resource 
            // during the Activated event handler because it increase the time 
            // it takes for the application to resume"
            host.IsResuming =
                Observable.FromEventPattern<ActivatedEventArgs>(
                    x => PhoneApplicationService.Current.Activated += x, x => PhoneApplicationService.Current.Activated -= x)
                    .Where(x => !x.EventArgs.IsApplicationInstancePreserved)
                    .Select(_ => Unit.Default)
                    .ObserveOn(RxApp.TaskpoolScheduler);

            // NB: No way to tell OS that we need time to suspend, we have to
            // do it in-process
            host.ShouldPersistState = Observable.Merge(
                Observable.FromEventPattern<DeactivatedEventArgs>(
                    x => PhoneApplicationService.Current.Deactivated += x, x => PhoneApplicationService.Current.Deactivated -= x)
                    .Select(_ => Disposable.Empty),
                Observable.FromEventPattern<ClosingEventArgs>(
                    x => PhoneApplicationService.Current.Closing += x, x => PhoneApplicationService.Current.Closing -= x)
                    .Select(_ => Disposable.Empty));

            host.ShouldInvalidateState =
                Observable.FromEventPattern<ApplicationUnhandledExceptionEventArgs>(x => UnhandledException += x, x => UnhandledException -= x)
                    .Select(_ => Unit.Default);

            SuspensionHost = host;

            //
            // Do the equivalent steps that the boilerplate code does for WP8 apps
            //

            if (RootFrame != null) return;
            RootFrame = new PhoneApplicationFrame();

            var currentBackHook = default(IDisposable);
            var currentViewFor = default(WeakReference<IViewFor>);

            RootFrame.Navigated += (o, e) => {
                // Always clear the WP8 Back Stack, we're using our own
                while (RootFrame.RemoveBackEntry() != null) {}

                if (currentBackHook != null) currentBackHook.Dispose();
                var page = RootFrame.Content as PhoneApplicationPage;
                if (page != null) {
                    currentBackHook = Observable.FromEventPattern<CancelEventArgs>(x => page.BackKeyPress += x, x => page.BackKeyPress -= x)
                        .Where(_ => ViewModel != null)
                        .Subscribe(x => {
                            if (!ViewModel.Router.NavigateBack.CanExecute(null)) return;

                            x.EventArgs.Cancel = true;
                            ViewModel.Router.NavigateBack.Execute(null);
                        });

                    var viewFor = page as IViewFor;
                    if (viewFor == null) {
                        throw new Exception("Your Main Page (i.e. the one that is pointed to by WMAppManifest) must implement IViewFor<YourAppBootstrapperClass>");
                    }

                    currentViewFor = new WeakReference<IViewFor>(viewFor);
                    viewFor.ViewModel = ViewModel;
                }

                // Finally make it live
                RootVisual = RootFrame;
            };

            _viewModelChanged.StartWith(ViewModel).Where(x => x != null).Subscribe(vm => {
                var viewFor = default(IViewFor);
                if (currentViewFor != null && currentViewFor.TryGetTarget(out viewFor)) {
                    viewFor.ViewModel = vm;
                }
            });

            UnhandledException += (o, e) => {
                if (Debugger.IsAttached) Debugger.Break();
            };

            RootFrame.NavigationFailed += (o, e) => {
                if (Debugger.IsAttached) Debugger.Break();
            };
        }
 static AndroidSuspensionHost()
 {
     inner = new SuspensionHost();
 }