So in my app when the time is up I want to launch an activity that notifies the user and then lets them dismiss the alarm.
I try to achieve it by scheduling an exact alarm and then launching a high priority notification with full-screen intent from my AlarmReceiver's onReceive()
. The problem is that the activity doesn't launch when the screen is locked, all I receive is a heads-up notification that doesn't even turn the screen on, nor vibrates. It doesn't launch on my phone (Xiaomi X4 with Android 7.1.2) but it did on another phone I tried (Samsung Galaxy A5 with Android 6). I know that this is possible to achieve on my phone as I've observed that other apps like clock, phone, whatsapp and so on can do this.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.App">
<activity
android:taskAffinity=""
android:launchMode="singleInstance"
android:showForAllUsers="true"
android:excludeFromRecents="true"
android:name=".TimeIsUpActivity" />
<activity
android:name=".MainActivity"
android:exported="true"
android:showOnLockScreen="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".AlarmReceiver"
android:enabled="true" />
</application>
</manifest>
val alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent ->
PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
val seconds = 5
alarmMgr.setExactAndAllowWhileIdle(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + seconds*1000,
alarmIntent
)
class AlarmReceiver: BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
context?.apply {
val fullScreenIntent = Intent(this, TimeIsUpActivity::class.java)
fullScreenIntent.flags =
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK or
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS or Intent.FLAG_ACTIVITY_NO_USER_ACTION
val fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val builder = NotificationCompat.Builder(this, getString(R.string.channel_id))
.setContentTitle("Time is up")
.setContentText("Tap to dismiss")
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setContentIntent(fullScreenPendingIntent)
.setSmallIcon(R.drawable.ic_add)
.setVibrate(longArrayOf(1000, 1000, 1000, 1000, 1000))
.setOngoing(true)
.setLights(0xFFFFFF, 1000, 1000)
.setCategory(NotificationCompat.CATEGORY_ALARM)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setFullScreenIntent(fullScreenPendingIntent, true)
val notificationId = Random().nextInt()
val notification = builder.build()
with(NotificationManagerCompat.from(this)) {
notify(notificationId, notification)
}
}
}
}
class TimeIsUpActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
turnScreenOnAndKeyguardOff()
setContentView(R.layout.activity_time_is_up)
}
private fun turnScreenOnAndKeyguardOff() {
if (Build.VERSION.SDK_INT >= 27) {
setShowWhenLocked(true)
setTurnScreenOn(true)
(getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager).also {
it.requestDismissKeyguard(this, null)
}
}
window.addFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or
WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON or
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
}
}
Please help me.
I found that it's because Xiaomi devices don't allow apps to show on lock screen by default. To allow it one has to go to settings -> permissions -> other permissions -> find your app -> check "Show on Lock screen". It might be different on newer devices.