1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package androidx.lifecycle
17 
18 import android.app.Activity
19 import android.app.Application
20 import android.content.Context
21 import android.os.Build
22 import android.os.Bundle
23 import android.os.Handler
24 import androidx.annotation.RequiresApi
25 import androidx.annotation.VisibleForTesting
26 import androidx.lifecycle.ReportFragment.Companion.reportFragment
27 
28 /**
29  * Class that provides lifecycle for the whole application process.
30  *
31  * You can consider this LifecycleOwner as the composite of all of your Activities, except that
32  * [Lifecycle.Event.ON_CREATE] will be dispatched once and [Lifecycle.Event.ON_DESTROY] will never
33  * be dispatched. Other lifecycle events will be dispatched with following rules:
34  * ProcessLifecycleOwner will dispatch [Lifecycle.Event.ON_START], [Lifecycle.Event.ON_RESUME]
35  * events, as a first activity moves through these events. [Lifecycle.Event.ON_PAUSE],
36  * [Lifecycle.Event.ON_STOP], events will be dispatched with a **delay** after a last activity
37  * passed through them. This delay is long enough to guarantee that ProcessLifecycleOwner won't send
38  * any events if activities are destroyed and recreated due to a configuration change.
39  *
40  * It is useful for use cases where you would like to react on your app coming to the foreground or
41  * going to the background and you don't need a milliseconds accuracy in receiving lifecycle events.
42  */
43 public class ProcessLifecycleOwner private constructor() : LifecycleOwner {
44     // ground truth counters
45     private var startedCounter = 0
46     private var resumedCounter = 0
47     private var pauseSent = true
48     private var stopSent = true
49     private var handler: Handler? = null
50     private val registry = LifecycleRegistry(this)
<lambda>null51     private val delayedPauseRunnable = Runnable {
52         dispatchPauseIfNeeded()
53         dispatchStopIfNeeded()
54     }
55     private val initializationListener: ReportFragment.ActivityInitializationListener =
56         object : ReportFragment.ActivityInitializationListener {
onCreatenull57             override fun onCreate() {}
58 
onStartnull59             override fun onStart() {
60                 activityStarted()
61             }
62 
onResumenull63             override fun onResume() {
64                 activityResumed()
65             }
66         }
67 
68     public companion object {
69         @VisibleForTesting internal const val TIMEOUT_MS: Long = 700 // mls
70         private val newInstance = ProcessLifecycleOwner()
71 
72         /**
73          * The LifecycleOwner for the whole application process. Note that if your application has
74          * multiple processes, this provider does not know about other processes.
75          *
76          * @return [LifecycleOwner] for the whole application.
77          */
78         @JvmStatic
getnull79         public fun get(): LifecycleOwner {
80             return newInstance
81         }
82 
83         @JvmStatic
initnull84         internal fun init(context: Context) {
85             newInstance.attach(context)
86         }
87     }
88 
activityStartednull89     internal fun activityStarted() {
90         startedCounter++
91         if (startedCounter == 1 && stopSent) {
92             registry.handleLifecycleEvent(Lifecycle.Event.ON_START)
93             stopSent = false
94         }
95     }
96 
activityResumednull97     internal fun activityResumed() {
98         resumedCounter++
99         if (resumedCounter == 1) {
100             if (pauseSent) {
101                 registry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
102                 pauseSent = false
103             } else {
104                 handler!!.removeCallbacks(delayedPauseRunnable)
105             }
106         }
107     }
108 
activityPausednull109     internal fun activityPaused() {
110         resumedCounter--
111         if (resumedCounter == 0) {
112             handler!!.postDelayed(delayedPauseRunnable, TIMEOUT_MS)
113         }
114     }
115 
activityStoppednull116     internal fun activityStopped() {
117         startedCounter--
118         dispatchStopIfNeeded()
119     }
120 
dispatchPauseIfNeedednull121     internal fun dispatchPauseIfNeeded() {
122         if (resumedCounter == 0) {
123             pauseSent = true
124             registry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
125         }
126     }
127 
dispatchStopIfNeedednull128     internal fun dispatchStopIfNeeded() {
129         if (startedCounter == 0 && pauseSent) {
130             registry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
131             stopSent = true
132         }
133     }
134 
135     @Suppress("DEPRECATION")
attachnull136     internal fun attach(context: Context) {
137         handler = Handler()
138         registry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
139         val app = context.applicationContext as Application
140         app.registerActivityLifecycleCallbacks(
141             object : EmptyActivityLifecycleCallbacks() {
142                 @RequiresApi(29)
143                 override fun onActivityPreCreated(activity: Activity, savedInstanceState: Bundle?) {
144                     // We need the ProcessLifecycleOwner to get ON_START and ON_RESUME precisely
145                     // before the first activity gets its LifecycleOwner started/resumed.
146                     // The activity's LifecycleOwner gets started/resumed via an activity registered
147                     // callback added in onCreate(). By adding our own activity registered callback
148                     // in
149                     // onActivityPreCreated(), we get our callbacks first while still having the
150                     // right relative order compared to the Activity's onStart()/onResume()
151                     // callbacks.
152                     Api29Impl.registerActivityLifecycleCallbacks(
153                         activity,
154                         object : EmptyActivityLifecycleCallbacks() {
155                             override fun onActivityPostStarted(activity: Activity) {
156                                 activityStarted()
157                             }
158 
159                             override fun onActivityPostResumed(activity: Activity) {
160                                 activityResumed()
161                             }
162                         }
163                     )
164                 }
165 
166                 override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
167                     // Only use ReportFragment pre API 29 - after that, we can use the
168                     // onActivityPostStarted and onActivityPostResumed callbacks registered in
169                     // onActivityPreCreated()
170                     if (Build.VERSION.SDK_INT < 29) {
171                         activity.reportFragment.setProcessListener(initializationListener)
172                     }
173                 }
174 
175                 override fun onActivityPaused(activity: Activity) {
176                     activityPaused()
177                 }
178 
179                 override fun onActivityStopped(activity: Activity) {
180                     activityStopped()
181                 }
182             }
183         )
184     }
185 
186     override val lifecycle: Lifecycle
187         get() = registry
188 
189     @RequiresApi(29)
190     internal object Api29Impl {
191         @JvmStatic
registerActivityLifecycleCallbacksnull192         fun registerActivityLifecycleCallbacks(
193             activity: Activity,
194             callback: Application.ActivityLifecycleCallbacks
195         ) {
196             activity.registerActivityLifecycleCallbacks(callback)
197         }
198     }
199 }
200