• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2024 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 com.android.photopicker.core.embedded
17 
18 import android.os.Bundle
19 import android.view.View
20 import androidx.activity.OnBackPressedDispatcher
21 import androidx.activity.OnBackPressedDispatcherOwner
22 import androidx.annotation.MainThread
23 import androidx.lifecycle.HasDefaultViewModelProviderFactory
24 import androidx.lifecycle.Lifecycle
25 import androidx.lifecycle.LifecycleOwner
26 import androidx.lifecycle.LifecycleRegistry
27 import androidx.lifecycle.ViewModelProvider
28 import androidx.lifecycle.ViewModelStore
29 import androidx.lifecycle.ViewModelStoreOwner
30 import androidx.lifecycle.setViewTreeLifecycleOwner
31 import androidx.lifecycle.setViewTreeViewModelStoreOwner
32 import androidx.lifecycle.viewmodel.CreationExtras
33 import androidx.savedstate.SavedStateRegistry
34 import androidx.savedstate.SavedStateRegistryController
35 import androidx.savedstate.SavedStateRegistryOwner
36 import androidx.savedstate.setViewTreeSavedStateRegistryOwner
37 
38 /**
39  * A custom [LifecycleOwner], [ViewModelStoreOwner], [OnBackPressedDispatcherOwner] and
40  * [SavedStateRegistryOwner] for use with the embedded runtime of Photopicker.
41  *
42  * This class is only used for Embedded Photopicker, it is not invoked during the regular,
43  * activity-based photopicker experience.
44  *
45  * IMPORTANT: It can only be created on the MainThread.
46  *
47  * The lifecycle is controlled by the [Session] class, and expects that all Lifecycle state changes
48  * are always called from the MainThread.
49  *
50  * The embedded photopicker is not run inside of the activity framework, however the compose UI
51  * requires certain activity provided conventions to run correctly, and for embedded photopicker
52  * sessions, this class provides all of that functionality to the embedded runtime.
53  *
54  * @property viewModelFactory A [ViewModelProvider.Factory] implementation that can build all of the
55  *   Photopicker [ViewModel] that are required during an embedded photopicker session.
56  * @see [EmbeddedViewModelFactory] for implementation of how view models are created during the
57  *   embedded runtime.
58  */
59 class EmbeddedLifecycle(viewModelFactory: ViewModelProvider.Factory) :
60     LifecycleOwner,
61     ViewModelStoreOwner,
62     SavedStateRegistryOwner,
63     OnBackPressedDispatcherOwner,
64     HasDefaultViewModelProviderFactory {
65 
66     companion object {
67         val TAG: String = "EmbeddedViewLifecycle"
68     }
69 
70     private val stateBundle: Bundle = Bundle()
71 
72     private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(/* provider= */ this)
73     private val savedStateRegistryController = SavedStateRegistryController.create(this)
74 
75     override val lifecycle: Lifecycle
76         get() = lifecycleRegistry
77 
78     override val savedStateRegistry: SavedStateRegistry =
79         savedStateRegistryController.savedStateRegistry
80 
81     init {
82 
83         // Initialize and attach the savedStateRegistryController.
84         lifecycleRegistry.currentState = Lifecycle.State.INITIALIZED
85         savedStateRegistryController.performAttach()
86         savedStateRegistryController.performRestore(stateBundle)
87     }
88 
89     /**
90      * This [OnBackPressedDispatcher] should be used to provide dispatcher for any
91      * [OnBackPressedCallback] in embedded session to [PhotopickerNavGraph]
92      */
93     override val onBackPressedDispatcher: OnBackPressedDispatcher = OnBackPressedDispatcher()
94 
95     /**
96      * This [ViewModelStore] holds all of the Photopicker view models for an individual embedded
97      * photopicker session.
98      */
99     override val viewModelStore: ViewModelStore = ViewModelStore()
100 
101     /**
102      * Returns the default [ViewModelProvider.Factory] that should be used when no custom `Factory`
103      * is provided to the [ViewModelProvider] constructors.
104      */
105     override val defaultViewModelProviderFactory: ViewModelProvider.Factory = viewModelFactory
106 
107     /**
108      * Returns the default [CreationExtras] that should be passed into
109      * [ViewModelProvider.Factory.create] when no overriding [CreationExtras] were passed to the
110      * [ViewModelProvider] constructors.
111      */
112     override val defaultViewModelCreationExtras: CreationExtras
113         get() = CreationExtras.Empty
114 
115     @MainThread
onCreatenull116     fun onCreate() {
117         lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
118     }
119 
120     @MainThread
onStartnull121     fun onStart() {
122         lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
123     }
124 
125     @MainThread
onResumenull126     fun onResume() {
127         lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
128     }
129 
130     @MainThread
onPausenull131     fun onPause() {
132         lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
133     }
134 
135     @MainThread
onStopnull136     fun onStop() {
137         lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
138     }
139 
140     @MainThread
onDestroynull141     fun onDestroy() {
142         savedStateRegistryController.performSave(stateBundle)
143         lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
144     }
145 
146     /**
147      * Sets the view tree owners for the given view.
148      *
149      * This should be done before setting the content view so that the inflation process and attach
150      * listeners will see them already present. They will be reused by any ComposeView inside the
151      * view's hierarchy.
152      *
153      * @param view The view to attach to this lifecycle.
154      */
attachViewnull155     fun attachView(view: View) {
156         view.setViewTreeLifecycleOwner(this)
157         view.setViewTreeViewModelStoreOwner(this)
158         view.setViewTreeSavedStateRegistryOwner(this)
159     }
160 }
161