title: How to set an alarm on Android Q?
body: <h2>Background</h2>
  
  <p>Android Q seems to have plenty of new restrictions, but alarms shouldn't be one of them:</p>
  
  <p><a href="https://developer.android.com/guide/components/activities/background-starts" rel="noreferrer">https://developer.android.com/guide/components/activities/background-starts</a></p>
  
  <h2>The problem</h2>
  
  <p>It seems that old code that I made for setting an alarm, which worked fine on P, can't work well anymore:</p>
  
  <p><strong>MainActivity.kt</strong></p>
  
  <pre><code>class MainActivity : AppCompatActivity() {
      private lateinit var manager: AlarmManager
  
      override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          setContentView(R.layout.activity_main)
          manager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
          button.setOnClickListener {
              Log.d("AppLog", "alarm set")
              Toast.makeText(this, "alarm set", Toast.LENGTH_SHORT).show()
              val timeToTrigger = System.currentTimeMillis() + 10 * 1000
              setAlarm(this, timeToTrigger, 1)
          }
      }
  
      companion object {
          fun setAlarm(context: Context, timeToTrigger: Long, requestId: Int) {
              val manager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
              val pendingIntent = PendingIntent.getBroadcast(context, requestId, Intent(context, AlarmReceiver::class.java), PendingIntent.FLAG_UPDATE_CURRENT)
              when {
                  VERSION.SDK_INT &gt;= VERSION_CODES.LOLLIPOP -&gt; manager.setAlarmClock(AlarmClockInfo(timeToTrigger, pendingIntent), pendingIntent)
                  VERSION.SDK_INT &gt;= VERSION_CODES.KITKAT -&gt; manager.setExact(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
                  else -&gt; manager.set(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
              }
          }
      }
  }
  </code></pre>
  
  <p>The receiver does get the Intent, but when it tries to open the Activity, sometimes nothing occurs:</p>
  
  <p><strong>AlarmReceiver.kt</strong></p>
  
  <pre><code>class AlarmReceiver : BroadcastReceiver() {
      override fun onReceive(context: Context, intent: Intent) {
          Log.d("AppLog", "AlarmReceiver onReceive")
          context.startActivity(Intent(context, Main2Activity::class.java).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
      }
  }
  </code></pre>
  
  <p>Seeing this as a bug, I reported <a href="https://issuetracker.google.com/issues/141052321" rel="noreferrer"><strong>here</strong></a> (including sample code)</p>
  
  <h2>What I've tried</h2>
  
  <p>I tried to find what's new on Q, to see what could cause it, and I couldn't find it.</p>
  
  <p>I also tried (if you look at the code) to directly open the Activity instead of via a BroadcastReceiver.</p>
  
  <p>And, I tried to set the BroadcastReceiver to run on a different process.</p>
  
  <p>All of those didn't help.</p>
  
  <p>What I have found is that while some alarm clock apps fail to work properly (such as <a href="https://play.google.com/store/apps/details?id=ch.bitspin.timely" rel="noreferrer"><strong>Timely</strong></a>), some apps work just fine (such as "<a href="https://play.google.com/store/apps/details?id=com.alarmclock.xtreme.free" rel="noreferrer">Alarm Clock Xtreme</a>").</p>
  
  <h2>The questions</h2>
  
  <ol>
  <li><p>On Android Q, is there an official way to let alarms work correctly? To open an Activity that will be shown to the user, exactly as an alarm clock app should?</p></li>
  <li><p>What's wrong in the code I've made? How come it works on P but not always on Q? </p></li>
  </ol>
  
  <hr>
  
  <p>EDIT: OK after being adviced to have a notification shown while I start the Activity, and also use FullScreenIntent, I got something to work, but it's only working when the screen is turned off. When the screen is turned on, it only shows the notification, which is a bad thing because the whole point is to have an alarm being shown to the user, and some users (like me) don't want to have heads-up-notification for alarms, popping out in the middle of something and not pausing anything. I hope someone can help with this, as this used to be a very easy thing to do, and now it got way too complex...</p>
  
  <p>Here's the current code (available <a href="https://issuetracker.google.com/issues/141052321#comment5" rel="noreferrer"><strong>here</strong></a>) :</p>
  
  <p><strong>NotificationId</strong></p>
  
  <pre><code>object NotificationId {
      const val ALARM_TRIGGERED = 1
      @JvmStatic
      private var hasInitialized = false
  
      @UiThread
      @JvmStatic
      fun initNotificationsChannels(context: Context) {
          if (hasInitialized || Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.O)
              return
          hasInitialized = true
          val channelsToUpdateOrAdd = HashMap&lt;String, NotificationChannel&gt;()
          val channel = NotificationChannel(context.getString(R.string.channel_id__alarm_triggered), context.getString(R.string.channel_name__alarm_triggered), NotificationManager.IMPORTANCE_HIGH)
          channel.description = context.getString(R.string.channel_description__alarm_triggered)
          channel.enableLights(true)
          channel.setSound(null, null)
          channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
          channel.enableVibration(false)
          channel.setShowBadge(false)
          channelsToUpdateOrAdd[channel.id] = channel
          //
          val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
          val existingChannels = notificationManager.notificationChannels
          if (existingChannels != null)
              for (existingChannel in existingChannels) {
                  //                The importance of an existing channel will only be changed if the new importance is lower than the current value and the user has not altered any settings on this channel.
                  //                The group an existing channel will only be changed if the channel does not already belong to a group. All other fields are ignored for channels that already exist.
                  val channelToUpdateOrAdd = channelsToUpdateOrAdd[existingChannel.id]
                  if (channelToUpdateOrAdd == null) //|| channelToUpdateOrAdd.importance &gt; existingChannel.importance || (existingChannel.group != null &amp;&amp; channelToUpdateOrAdd.group != existingChannel.group))
                      notificationManager.deleteNotificationChannel(existingChannel.id)
              }
          for (notificationChannel in channelsToUpdateOrAdd.values) {
              notificationManager.createNotificationChannel(notificationChannel)
          }
      }
  }
  </code></pre>
  
  <p><strong>MyService.kt</strong></p>
  
  <pre><code>class MyService : Service() {
      override fun onBind(p0: Intent?): IBinder? = null
      override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
          Log.d("AppLog", "MyService onStartCommand")
          if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.O) {
              NotificationId.initNotificationsChannels(this)
              val builder = NotificationCompat.Builder(this, getString(R.string.channel_id__alarm_triggered)).setSmallIcon(android.R.drawable.sym_def_app_icon) //
                      .setPriority(NotificationCompat.PRIORITY_HIGH).setCategory(NotificationCompat.CATEGORY_ALARM)
              builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
              builder.setShowWhen(false)
              builder.setContentText("Alarm is triggered!")
              builder.setContentTitle("Alarm!!!")
              val fullScreenIntent = Intent(this, Main2Activity::class.java)
              val fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
                      fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT)
              builder.setFullScreenIntent(fullScreenPendingIntent, true)
              startForeground(NotificationId.ALARM_TRIGGERED, builder.build())
              startActivity(Intent(this, Main2Activity::class.java).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
              Handler().postDelayed({
                  stopForeground(true)
                  stopSelf()
              }, 2000L)
          } else {
              startActivity(Intent(this, Main2Activity::class.java).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
          }
          return super.onStartCommand(intent, flags, startId)
      }
  }
  </code></pre>
  
  <p><strong>MainActivity.kt</strong></p>
  
  <pre><code>class MainActivity : AppCompatActivity() {
      private lateinit var manager: AlarmManager
  
      override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          setContentView(R.layout.activity_main)
          manager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
          button.setOnClickListener {
              Log.d("AppLog", "alarm set")
              Toast.makeText(this, "alarm set", Toast.LENGTH_SHORT).show()
              val timeToTrigger = System.currentTimeMillis() + 10 * 1000
              setAlarm(this, timeToTrigger, 1)
          }
      }
  
      companion object {
          fun setAlarm(context: Context, timeToTrigger: Long, requestId: Int) {
              val manager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
                          val pendingIntent = PendingIntent.getBroadcast(context, requestId, Intent(context, AlarmReceiver::class.java), PendingIntent.FLAG_UPDATE_CURRENT)
              //            val pendingIntent = PendingIntent.getBroadcast(context, requestId, Intent(context, Main2Activity::class.java), PendingIntent.FLAG_UPDATE_CURRENT)
  //            val pendingIntent = PendingIntent.getService(context, requestId, Intent(context, MyService::class.java), PendingIntent.FLAG_UPDATE_CURRENT)
              when {
                  VERSION.SDK_INT &gt;= VERSION_CODES.LOLLIPOP -&gt; manager.setAlarmClock(AlarmClockInfo(timeToTrigger, pendingIntent), pendingIntent)
                  VERSION.SDK_INT &gt;= VERSION_CODES.KITKAT -&gt; manager.setExact(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
                  else -&gt; manager.set(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
              }
          }
      }
  }
  </code></pre>
  
  <p><strong>AlarmReceiver.kt</strong></p>
  
  <pre><code>class AlarmReceiver : BroadcastReceiver() {
      override fun onReceive(context: Context, intent: Intent) {
          Log.d("AppLog", "AlarmReceiver onReceive")
          if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.O) {
              context.startForegroundService(Intent(context, MyService::class.java))
          } else context.startService(Intent(context, MyService::class.java))
      }
  }
  </code></pre>