Search code examples
xamarinandroid-activityservice

Open a Activity from a service


I have a service on my app that starts one activity. When the app is on back or foreground the service can open the activity, but when the app is dead and the service try to open it, nothing hapen. So, the service neeeds to start the activity even that the app is dead. Can somebody help?

That's the class of service:

[Service]
    public class TimestampService : Service
    {
        static readonly string TAG = typeof(TimestampService).FullName;
        static readonly int DELAY_BETWEEN_LOG_MESSAGES = 5000; // milliseconds
        static readonly int NOTIFICATION_ID = 10000;
        static readonly string SERVICE_STARTED_KEY = "has_service_been_started";

        UtcTimestamper timestamper;
        int hourExecute = 0 ;
        int minutoExecute = 0;
        bool isStarted;
        Handler handler;
        Action runnable;
        bool opened = false;

        public override void OnCreate()
        {
            base.OnCreate();
            Log.Info(TAG, "OnCreate: the service is initializing.");

            this.timestamper = new UtcTimestamper();
            this.handler = new Handler();

            // This Action is only for demonstration purposes.
            this.runnable = new Action(() =>
            {
                this.OpenAtivity();
            });
        }

        private void OpenAtivity()
        {
            if (this.timestamper != null)
            {
                Log.Debug(TAG, this.timestamper.GetFormattedTimestamp());

                if (DateTime.Now.Hour == 18 && DateTime.Now.Minute == 16 && !this.opened)
                {
                    this.TrySend();
                    this.opened = true;
                }

                //}                   
                this.handler.PostDelayed(this.runnable, DELAY_BETWEEN_LOG_MESSAGES);
            }
        }

        private void TrySend()
        {
            this.StartForeground(0, new Notification());

            /*
            Intent launchIntent = Application.Context.PackageManager.GetLaunchIntentForPackage(Application.Context.PackageName);
            Intent mainIntent = Intent.MakeRestartActivityTask(launchIntent.Component);
            StartActivity(mainIntent);
            */

            Intent launchIntent = Application.Context.PackageManager.GetLaunchIntentForPackage(Application.Context.PackageName);
            Intent mainIntent = Intent.MakeRestartActivityTask(launchIntent.Component);
            mainIntent.AddFlags(ActivityFlags.NewTask);
            mainIntent.PutExtra(SERVICE_STARTED_KEY, true);
            this.StartActivity(mainIntent);
        }

        public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
        {
            if (isStarted)
            {
                Log.Info(TAG, "OnStartCommand: This service has already been started.");
            }
            else
            {
                Log.Info(TAG, "OnStartCommand: The service is starting.");
                handler.PostDelayed(runnable, DELAY_BETWEEN_LOG_MESSAGES);
                isStarted = true;
            }
            handler.PostDelayed(runnable, DELAY_BETWEEN_LOG_MESSAGES);

            // This tells Android not to restart the service if it is killed to reclaim resources.
            return StartCommandResult.NotSticky;
        }


        public override IBinder OnBind(Intent intent)
        {
            // Return null because this is a pure started service. A hybrid service would return a binder that would
            // allow access to the GetFormattedStamp() method.
            return null;
        }


        public override void OnDestroy()
        {
            // We need to shut things down.
            Log.Debug(TAG, GetFormattedTimestamp());
            Log.Info(TAG, "OnDestroy: The started service is shutting down.");

            // Stop the handler.
            handler.RemoveCallbacks(runnable);

            // Remove the notification from the status bar.
            var notificationManager = (NotificationManager)GetSystemService(NotificationService);
            notificationManager.Cancel(NOTIFICATION_ID);

            timestamper = null;
            isStarted = false;
            base.OnDestroy();
        }

        /// <summary>
        /// This method will return a formatted timestamp to the client.
        /// </summary>
        /// <returns>A string that details what time the service started and how long it has been running.</returns>
        string GetFormattedTimestamp()
        {
            return timestamper?.GetFormattedTimestamp();
        }
    }

Solution

  • I gave up by use service to do this job. To solve the problem I created an alarm that opens the app when it's dead.

    This is a part of calling the service:

    private void StartAlarm()
        {
            AlarmManager manager = (AlarmManager)GetSystemService(AlarmService);
            Intent minhaIntent;
            PendingIntent pendingIntent;
            minhaIntent = new Intent(this, new BroadCast.OpenApp(this).Class);
            pendingIntent = PendingIntent.GetBroadcast(this, 0, minhaIntent, 0);
            int hour = 12;
            int minute = 25;
            DateTime time = new DateTime(2020, 11, 19, hour, minute, 0, DateTimeKind.Utc);
            manager.SetRepeating(AlarmType.RtcWakeup, (long)time.ToUniversalTime().Subtract(time).TotalMilliseconds, 60 * 1000, pendingIntent);
        }
    

    And this is my class:

    public override void OnReceive(Context context, Intent intent)
        {
            if (this.executed)
                return;
    
            else if (DateTime.Now.Minute != 55)
                return;
    
            this.executed = true;
            Toast.MakeText(context, "Descarregando", ToastLength.Short).Show();
            Intent mainIntent = Intent.MakeRestartActivityTask(launchIntent.Component);
    
            mainIntent.PutExtra(SERVICE_STARTED_KEY, true);
            context.StartActivity(mainIntent);
        }