When I receive a Push message in a service that extends FirebaseMessagingService and I start an Activity in this class, then the following lifecycle events / methods get executed:
- Push Message starts VideoRingingActivity
- Start VideoRingingActivity
- onCreate
- disableLockScreen
- The screen switches from black to the lock screen,
so it doesn't show the VideoRingingActivity
- onStart
- onResume
- onPause
- onStop
- Now the actual VideoRingingActivity is shown? I was expecting
this to come up after setContentView(R.layout.activity_video_ringing)
- onRestart
- onStart
- onResume
I have developed below work-around solution where I add a boolean, to determine if the screen is on / off. But this is hacky and when the screen is on in Lock mode then it doesn't work.
Because when the screen is not turned off and MainActivity is shown, and the push message is received, then the behaviour is default Lifecycle behaviour and thus correct. Here is the same flow when the screen is turned on and MainActivity is shown:
- onCreate
- onStart
- onResume
This is correct and to be expected.
class VideoRingingActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
if (ViewUtils.isScreenActive(activity)) {
screenIsNotLocked = true
}
ViewUtils.disableLockScreen(this)
binding = DataBindingUtil.setContentView(this, R.layout.activity_video_ringing)
}
override fun onStart() {
super.onStart()
if (screenIsNotLocked) {
}
}
override fun onResume() {
super.onResume()
if (screenIsNotLocked) {
}
}
override fun onPause() {
super.onPause()
if (screenIsNotLocked) {
}
}
override fun onStop() {
super.onStop()
if (screenIsNotLocked) {
}
screenIsNotLocked = true
}
}
open class ViewUtils {
@JvmStatic
@Suppress("DEPRECATION")
fun disableLockScreen(activity: Activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
activity.setShowWhenLocked(true)
activity.setTurnScreenOn(true)
}
val lock = (activity.getSystemService(Activity.KEYGUARD_SERVICE) as KeyguardManager).newKeyguardLock(Context.KEYGUARD_SERVICE)
val powerManager = activity.getSystemService(Context.POWER_SERVICE) as PowerManager
val wake = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK or PowerManager.ACQUIRE_CAUSES_WAKEUP or PowerManager.ON_AFTER_RELEASE, "BusSnoozeAlarm")
lock.disableKeyguard()
wake.acquire(TIMEOUT)
activity.window.addFlags(
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
or WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON)
}
@Suppress("DEPRECATION")
fun isScreenActive(context: Context): Boolean {
val powerManager = context.getSystemService(POWER_SERVICE) as PowerManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
return powerManager.isInteractive
} else {
return powerManager.isScreenOn
}
}
}
UPDATE: There is another SO thread that has a similar problem, but the solution is outdated and doesn't account for the corner case when the screen is active in lock screen mode:
OnPause and OnStop() called immediately after starting activity
Why the onPause method is called immediately after onCreate
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…