Search code examples
c#androidxamarinbroadcastreceiverforeground-service

How to launch app page from power button automatically on Android


I'm making a little app for my niece using Xamarin Android in VS 2017. I want it to open a page on the app that asks her a simple multiplication question every time she opens the phone. I want it to run as a foreground service so it still does it when the app is minimised. I've got a broadcast receiver that detected the button event while the app had focus and I've moved it to the service to run.

Currently I press the toggle button and then 5-10 seconds later it throws an error. Can't see the error in VS because it's external. I assume that's Genymotion emulator catching that then?

Any ideas?

UPDATE: I thought I'd come and update this if it's any use to anyone else in the future. After the Oreo update NotificationCompat.Builder now needs the channel ID supplying. I've reflected that in the code and it now launches the service correctly.

I still need to get the broadcast receiver working from the service but I'm getting there!

UPDATE 2: Job done!

[Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
    Intent startServiceIntent;
    Intent stopServiceIntent;

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        SetContentView(Resource.Layout.activity_main);

        // Difficulty Radio Buttons
        RadioButton radioEasy = FindViewById<RadioButton>(Resource.Id.radioEasy);
        radioEasy.Click += RadioButton_Click;
        RadioButton radioMedium = FindViewById<RadioButton>(Resource.Id.radioMedium);
        radioMedium.Click += RadioButton_Click;
        RadioButton radioHard = FindViewById<RadioButton>(Resource.Id.radioHard);
        radioHard.Click += RadioButton_Click;

        // Set/Remove Lock
        Button ToggleLock = FindViewById<Button>(Resource.Id.ToggleLock);
        ToggleLock.Click += ToggleLock_Click;

        startServiceIntent = new Intent(this, typeof(LockService));
        stopServiceIntent = new Intent(this, typeof(LockService));
    }

    private void RadioButton_Click(object sender, EventArgs e)
    {
        var radiobtn = sender as RadioButton;
        Toast.MakeText(this, radiobtn.Text, ToastLength.Long).Show();
    }
    private void ToggleLock_Click(object sender, EventArgs e)
    {
        var togglebtn = sender as ToggleButton;
        if (togglebtn.Checked)
        {
            if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
                StartForegroundService(startServiceIntent);
            else
                StartService(startServiceIntent);

            Toast.MakeText(this, "On", ToastLength.Long).Show();
        }
        else
        {
            Toast.MakeText(this, "Off", ToastLength.Long).Show();
        }
    }
}


/// <summary>
/// ////////////////////////////////////////////////////////////////////////////
/// </summary>

[Service]
public class LockService : Service
{
    private PowerBroadcastReceiver receiver;

    public override void OnCreate()
    {
    }

    public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
    {
        NotificationManager mngr = (NotificationManager)GetSystemService(NotificationService);
        NotificationChannel chnl = new NotificationChannel("Channel", "Name", NotificationImportance.Default);
        mngr.CreateNotificationChannel(chnl);

        NotificationCompat.Builder foregroundNotification = new NotificationCompat.Builder(this);
        foregroundNotification.SetOngoing(true);
        foregroundNotification.SetContentTitle("My Foreground Notification")
                .SetChannelId("Channel")
                .SetContentText("This is the first foreground notification Peace");

        StartForeground(101, foregroundNotification.Notification);

        // Broadcast Receiver
        receiver = new PowerBroadcastReceiver();
        RegisterReceiver(receiver, new IntentFilter(Intent.ActionScreenOn));

        return StartCommandResult.Sticky;
    }

    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;
    }

}

/// <summary>
/// ////////////////////////////////////////////////////////////////////////////////
/// </summary>

[BroadcastReceiver]
[IntentFilter(new[] { Intent.ActionScreenOn, Intent.ActionScreenOff })]
public class PowerBroadcastReceiver : BroadcastReceiver
{
    public PowerBroadcastReceiver()
    {
    }

    public override void OnReceive(Context context, Intent intent)
    {
        if (intent.Action.Equals(Intent.ActionScreenOn))
        {
            // TODO: Launch Question Page

            Toast.MakeText(context, "On", ToastLength.Long).Show();
        }
        else if (intent.Action.Equals(Intent.ActionScreenOff))
            Toast.MakeText(context, "Off", ToastLength.Long).Show();
    }
}

Thanks.


Solution

  • you could create a listener class to listen for android lock screen and unlock events,use broadcast to receive the state of screen. As it's a system broadcast, i don't think it's necessary to use Service .

    you could refer to this:https://stackoverflow.com/a/55014763/10768653