public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
        {
            AndroidSensusServiceHelper serviceHelper = SensusServiceHelper.Get() as AndroidSensusServiceHelper;

            // there might be a race condition between the calling of this method and the stopping/disposal of the service helper.
            // if the service helper is stopped/disposed before the service is stopped but after this method is called (e.g., by
            // an alarm callback), the service helper will be null.
            if (serviceHelper != null)
            {
                serviceHelper.Logger.Log("Sensus service received start command (startId=" + startId + ", flags=" + flags + ").", LoggingLevel.Normal, GetType());

                // update the foreground service notification with information about loaded/running studies.
                (SensusContext.Current.Notifier as AndroidNotifier).ReissueForegroundServiceNotification();

                // if the service started but there are no protocols that should be running, then stop the app now. there is no
                // reason for the app to be running in this situation, and the user will likely be annoyed at the presence of the
                // foreground service notification.
                if (intent != null && intent.GetBooleanExtra(KEY_STOP_SERVICE_IF_NO_PROTOCOLS_SHOULD_RUN, false) && serviceHelper.RunningProtocolIds.Count == 0)
                {
                    serviceHelper.Logger.Log("Started service without running protocols. Stopping service now.", LoggingLevel.Normal, GetType());
                    Stop();
                    return(StartCommandResult.NotSticky);
                }

                // acquire wake lock before this method returns to ensure that the device does not sleep prematurely, interrupting the execution of a callback.
                serviceHelper.KeepDeviceAwakeAsync().Wait();

                Task.Run(async() =>
                {
                    try
                    {
                        // the service can be stopped without destroying the service object. in such cases,
                        // subsequent calls to start the service will not call OnCreate. therefore, it's
                        // important that any code called here is okay to call multiple times, even if the
                        // service is running. calling this when the service is running can happen because
                        // sensus receives a signal on device boot and for any callback alarms that are
                        // requested. furthermore, all calls here should be nonblocking / async so we don't
                        // tie up the UI thread.
                        await serviceHelper.StartAsync();

                        if (intent != null)
                        {
                            AndroidCallbackScheduler callbackScheduler = SensusContext.Current.CallbackScheduler as AndroidCallbackScheduler;

                            if (callbackScheduler.IsCallback(intent))
                            {
                                await callbackScheduler.RaiseCallbackAsync(intent);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        serviceHelper.Logger.Log("Exception while responding to on-start command:  " + ex.Message, LoggingLevel.Normal, GetType());
                    }
                    finally
                    {
                        serviceHelper.LetDeviceSleepAsync().Wait();
                    }
                });
            }

            // if the service is killed by the system (e.g., due to resource constraints), ask the system to restart
            // the service when possible.
            return(StartCommandResult.Sticky);
        }
Beispiel #2
0
        public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
        {
            AndroidSensusServiceHelper serviceHelper = SensusServiceHelper.Get() as AndroidSensusServiceHelper;

            // there might be a race condition between the calling of this method and the stopping/disposal of the service helper.
            // if the service helper is stopped/disposed before the service is stopped but after this method is called (e.g., by
            // an alarm callback), the service helper will be null.
            if (serviceHelper != null)
            {
                serviceHelper.Logger.Log("Sensus service received start command (startId=" + startId + ", flags=" + flags + ").", LoggingLevel.Normal, GetType());

                // promote this service to a foreground, for several reasons:  it's honest and transparent. it lets us work effectively with the
                // android 8.0 restrictions on background services (we can run forever without being killed, we receive background location
                // updates). it's okay to call this multiple times. doing so will simply update the notification.
                if (_foregroundServiceNotificationBuilder == null)
                {
                    PendingIntent mainActivityPendingIntent = PendingIntent.GetActivity(this, 0, new Intent(this, typeof(AndroidMainActivity)), 0);
                    _foregroundServiceNotificationBuilder = (SensusContext.Current.Notifier as AndroidNotifier).CreateNotificationBuilder(this, AndroidNotifier.SensusNotificationChannel.ForegroundService)
                                                            .SetSmallIcon(Resource.Drawable.ic_launcher)
                                                            .SetContentIntent(mainActivityPendingIntent)
                                                            .SetOngoing(true);
                    UpdateForegroundServiceNotificationBuilder();
                    StartForeground(FOREGROUND_SERVICE_NOTIFICATION_ID, _foregroundServiceNotificationBuilder.Build());
                }
                else
                {
                    ReissueForegroundServiceNotification();
                }

                // acquire wake lock before this method returns to ensure that the device does not sleep prematurely, interrupting the execution of a callback.
                serviceHelper.KeepDeviceAwake();

                Task.Run(async() =>
                {
                    // the service can be stopped without destroying the service object. in such cases,
                    // subsequent calls to start the service will not call OnCreate. therefore, it's
                    // important that any code called here is okay to call multiple times, even if the
                    // service is running. calling this when the service is running can happen because
                    // sensus receives a signal on device boot and for any callback alarms that are
                    // requested. furthermore, all calls here should be nonblocking / async so we don't
                    // tie up the UI thread.
                    await serviceHelper.StartAsync();

                    if (intent == null)
                    {
                        serviceHelper.LetDeviceSleep();
                    }
                    else
                    {
                        AndroidCallbackScheduler callbackScheduler = SensusContext.Current.CallbackScheduler as AndroidCallbackScheduler;

                        DisplayPage displayPage;

                        // is this a callback intent?
                        if (callbackScheduler.IsCallback(intent))
                        {
                            // service the callback -- the matching LetDeviceSleep will be called therein
                            await callbackScheduler.ServiceCallbackAsync(intent);
                        }
                        // should we display a page?
                        else if (Enum.TryParse(intent.GetStringExtra(Notifier.DISPLAY_PAGE_KEY), out displayPage))
                        {
                            await serviceHelper.BringToForegroundAsync();
                            SensusContext.Current.Notifier.OpenDisplayPage(displayPage);
                            serviceHelper.LetDeviceSleep();
                        }
                        else
                        {
                            serviceHelper.LetDeviceSleep();
                        }
                    }
                });
            }

            // if the service is killed by the system (e.g., due to resource constraints), ask the system to restart
            // the service when possible.
            return(StartCommandResult.Sticky);
        }