Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
294 views
in Technique[技术] by (71.8m points)

android - How wake up device and show an activity on top of lock screen for alarm?

I have an old android app with an alarm where the user can set a time and alarm behavior like ringtone and ring duration, volume, if it only vibrates or if it's silent. It was working but it stopped working a long time ago due to new android rules and just now I had time to update it but I can't find an up-to-date answer to these questions.

Once the alarm is due I need to open an activity, on top of anything, including another app or lock screen, just like the default android alarm or an incoming call. This activity will have a message and a button to dismiss. Once dismissed I need the phone state back to where it was before.

I can set the alarm and it works, the BroadcastReceiver opens the activity if the app is in the foreground or background, but not if the app was forced to close. It pops-up the default crash message that my app stopped. Plus, I have no idea of how to make it opens on top of any lock screen.

I'm guessing it's because of missing permissions or flags.

I'm working with Xamarin so if you don't know it all you need to know is that the activities metadata are set on the class and compiled afterwards to the manifest.

Here's the activity I want to show when the alarm ends (not the main activity):

[Activity(Label = "@string/app_name", Theme = "@style/MainTheme.StopAlarm", LaunchMode = Android.Content.PM.LaunchMode.SingleTask)]
public class StopAlarmActivity : Activity
{

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        SetContentView(Resource.Layout.StopAlarmLayout);

        Bundle bundle = Intent.Extras;
        string msg = bundle.GetString("message");

        TextView nameTV = FindViewById<TextView>(Resource.Id.alarmTextView);
        nameTV.Text = msg;

        Button okButton = FindViewById<Button>(Resource.Id.okButton);
        okButton.Text = AppResources.OK;
        okButton.Click += (object sender, EventArgs args) =>
        {
            Finish();
        };
    }
}

My receiver:

[BroadcastReceiver]
    public class AlarmReceiver : BroadcastReceiver
    {

        public override void OnReceive(Context context, Intent intent)
        {
            Toast.MakeText(context, "Alarm worked.", ToastLength.Long).Show();

            string msg = intent.Extras.GetString("message");

            var myIntent = new Intent(context, typeof(StopAlarmActivity));
            Bundle bundle = new Bundle();
            bundle.PutString("message", msg);
            myIntent.PutExtras(bundle);
            myIntent.SetFlags(ActivityFlags.FromBackground);
            myIntent.SetFlags(ActivityFlags.NewTask);
            myIntent.AddCategory(Intent.CategoryLauncher);
            Forms.Context.StartActivity(myIntent);
        }
    }

Please don't waste your time telling me that this behavior should be avoided. It's an alarm, it's meant to wake him up if set by himself. Plus, the default android alarm doesn't do what my users want to do. The alarms are previously set based on some data in the app as a suggestion. The user has to run them and it's highly customizable for his needs.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Just have to set the correct window flags. This works from API 14(?) up to Oreo Beta:

Activity:

[Activity(Label = "AlarmActivity")]
public class AlarmActivity : Activity, View.IOnClickListener
{
    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        SetContentView(Resource.Layout.Alarm);
        FindViewById<Button>(Resource.Id.myButton).SetOnClickListener(this);
    }

    public override void OnAttachedToWindow()
    {
        Window.AddFlags(WindowManagerFlags.ShowWhenLocked | 
                        WindowManagerFlags.KeepScreenOn | 
                        WindowManagerFlags.DismissKeyguard | 
                        WindowManagerFlags.TurnScreenOn);
    }

    public void OnClick(View v)
    {
        Finish();
    }
}

AlarmManager Test:

Call this routine and the alarm manager will start up the AlarmActivity in one minute, so apply this within a Button click/listener and lock your screen:

using (var manager = (Android.App.AlarmManager)GetSystemService(AlarmService))
using (var calendar = Calendar.Instance)
{
    calendar.Add(CalendarField.Minute, 1);
    Log.Debug("SO", $"Current date is   : {Calendar.Instance.Time.ToString()}");
    Log.Debug("SO", $"Alarm will fire at {calendar.Time.ToString()}");
    var alarmIntent = new Intent(ApplicationContext, typeof(AlarmActivity));
    var pendingIntent = PendingIntent.GetActivity(this, 0, alarmIntent, PendingIntentFlags.OneShot);
    manager.SetExact(AlarmType.RtcWakeup, calendar.TimeInMillis, pendingIntent);
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...