• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 
17 package com.android.launcher3.util
18 
19 import android.content.Context
20 import android.view.ContextThemeWrapper
21 import android.view.View
22 import android.view.View.OnAttachStateChangeListener
23 import android.view.ViewTreeObserver.OnWindowFocusChangeListener
24 import android.view.ViewTreeObserver.OnWindowVisibilityChangeListener
25 import androidx.lifecycle.Lifecycle
26 import androidx.lifecycle.Lifecycle.State.CREATED
27 import androidx.lifecycle.Lifecycle.State.DESTROYED
28 import androidx.lifecycle.Lifecycle.State.RESUMED
29 import androidx.lifecycle.Lifecycle.State.STARTED
30 import androidx.lifecycle.LifecycleRegistry
31 import androidx.lifecycle.setViewTreeLifecycleOwner
32 import androidx.savedstate.SavedStateRegistry
33 import androidx.savedstate.SavedStateRegistryController
34 import androidx.savedstate.setViewTreeSavedStateRegistryOwner
35 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener
36 import com.android.launcher3.Utilities
37 import com.android.launcher3.views.ActivityContext
38 
39 /**
40  * A context wrapper with lifecycle tracking based on the window events on the rootView of the
41  * [ActivityContext]
42  */
43 abstract class BaseContext
44 @JvmOverloads
45 constructor(base: Context, themeResId: Int, private val destroyOnDetach: Boolean = true) :
46     ContextThemeWrapper(base, themeResId), ActivityContext {
47 
48     private val listeners = mutableListOf<OnDeviceProfileChangeListener>()
49 
50     private val savedStateRegistryController = SavedStateRegistryController.create(this)
51     private val lifecycleRegistry = LifecycleRegistry(this)
52     private val cleanupSet = WeakCleanupSet(this)
53 
54     override val savedStateRegistry: SavedStateRegistry
55         get() = savedStateRegistryController.savedStateRegistry
56 
57     override val lifecycle: Lifecycle
58         get() = lifecycleRegistry
59 
60     private val viewCache = ViewCache()
61 
62     init {
<lambda>null63         Executors.MAIN_EXECUTOR.execute {
64             savedStateRegistryController.performAttach()
65             savedStateRegistryController.performRestore(null)
66         }
67     }
68 
getOnDeviceProfileChangeListenersnull69     override fun getOnDeviceProfileChangeListeners() = listeners
70 
71     private val finishActions = RunnableList()
72 
73     /** Called when the root view is created for this context */
74     fun onViewCreated() {
75         val view = rootView
76         val attachListener =
77             object : OnAttachStateChangeListener {
78 
79                 override fun onViewAttachedToWindow(view: View) {
80                     view.rootView.setViewTreeLifecycleOwner(this@BaseContext)
81                     view.rootView.setViewTreeSavedStateRegistryOwner(this@BaseContext)
82                     lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
83 
84                     val treeObserver = view.viewTreeObserver
85 
86                     val focusListener = OnWindowFocusChangeListener { updateState() }
87                     treeObserver.addOnWindowFocusChangeListener(focusListener)
88                     finishActions.add {
89                         treeObserver.removeOnWindowFocusChangeListener(focusListener)
90                     }
91 
92                     if (Utilities.ATLEAST_V) {
93                         val visibilityListener = OnWindowVisibilityChangeListener { updateState() }
94                         treeObserver.addOnWindowVisibilityChangeListener(visibilityListener)
95                         finishActions.add {
96                             treeObserver.removeOnWindowVisibilityChangeListener(visibilityListener)
97                         }
98                     }
99                 }
100 
101                 override fun onViewDetachedFromWindow(view: View) {
102                     if (destroyOnDetach) onViewDestroyed()
103                 }
104             }
105         view.addOnAttachStateChangeListener(attachListener)
106         finishActions.add { view.removeOnAttachStateChangeListener(attachListener) }
107 
108         if (view.isAttachedToWindow) attachListener.onViewAttachedToWindow(view)
109         updateState()
110     }
111 
getViewCachenull112     override fun getViewCache() = viewCache
113 
114     override fun getOwnerCleanupSet() = cleanupSet
115 
116     private fun updateState() {
117         if (lifecycleRegistry.currentState.isAtLeast(CREATED)) {
118             lifecycleRegistry.currentState =
119                 if (rootView.windowVisibility != View.VISIBLE) CREATED
120                 else (if (!rootView.hasWindowFocus()) STARTED else RESUMED)
121         }
122     }
123 
onViewDestroyednull124     fun onViewDestroyed() {
125         if (
126             !lifecycleRegistry.currentState.isAtLeast(CREATED) &&
127                 lifecycleRegistry.currentState != DESTROYED
128         ) {
129             lifecycleRegistry.currentState = CREATED
130         }
131         lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
132         finishActions.executeAllAndDestroy()
133     }
134 }
135