1 /*
2  * Copyright 2018 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 androidx.fragment.app;
18 
19 import android.app.Application;
20 import android.content.Context;
21 import android.content.ContextWrapper;
22 import android.os.Bundle;
23 
24 import androidx.annotation.CallSuper;
25 import androidx.lifecycle.HasDefaultViewModelProviderFactory;
26 import androidx.lifecycle.Lifecycle;
27 import androidx.lifecycle.LifecycleRegistry;
28 import androidx.lifecycle.SavedStateHandleSupport;
29 import androidx.lifecycle.SavedStateViewModelFactory;
30 import androidx.lifecycle.ViewModelProvider;
31 import androidx.lifecycle.ViewModelStore;
32 import androidx.lifecycle.ViewModelStoreOwner;
33 import androidx.lifecycle.viewmodel.CreationExtras;
34 import androidx.lifecycle.viewmodel.MutableCreationExtras;
35 import androidx.savedstate.SavedStateRegistry;
36 import androidx.savedstate.SavedStateRegistryController;
37 import androidx.savedstate.SavedStateRegistryOwner;
38 
39 import org.jspecify.annotations.NonNull;
40 import org.jspecify.annotations.Nullable;
41 
42 class FragmentViewLifecycleOwner implements HasDefaultViewModelProviderFactory,
43         SavedStateRegistryOwner, ViewModelStoreOwner {
44     private final Fragment mFragment;
45     private final ViewModelStore mViewModelStore;
46     private final Runnable mRestoreViewSavedStateRunnable;
47 
48     private ViewModelProvider.Factory mDefaultFactory;
49 
50     private LifecycleRegistry mLifecycleRegistry = null;
51     private SavedStateRegistryController mSavedStateRegistryController = null;
52 
FragmentViewLifecycleOwner( @onNull Fragment fragment, @NonNull ViewModelStore viewModelStore, @NonNull Runnable restoreViewSavedStateRunnable )53     FragmentViewLifecycleOwner(
54             @NonNull Fragment fragment,
55             @NonNull ViewModelStore viewModelStore,
56             @NonNull Runnable restoreViewSavedStateRunnable
57     ) {
58         mFragment = fragment;
59         mViewModelStore = viewModelStore;
60         mRestoreViewSavedStateRunnable = restoreViewSavedStateRunnable;
61     }
62 
63     @Override
getViewModelStore()64     public @NonNull ViewModelStore getViewModelStore() {
65         initialize();
66         return mViewModelStore;
67     }
68 
69     /**
70      * Initializes the underlying Lifecycle if it hasn't already been created.
71      */
initialize()72     void initialize() {
73         if (mLifecycleRegistry == null) {
74             mLifecycleRegistry = new LifecycleRegistry(this);
75             mSavedStateRegistryController = SavedStateRegistryController.create(this);
76             mSavedStateRegistryController.performAttach();
77             mRestoreViewSavedStateRunnable.run();
78         }
79     }
80 
81     /**
82      * @return True if the Lifecycle has been initialized.
83      */
isInitialized()84     boolean isInitialized() {
85         return mLifecycleRegistry != null;
86     }
87 
88     @Override
getLifecycle()89     public @NonNull Lifecycle getLifecycle() {
90         initialize();
91         return mLifecycleRegistry;
92     }
93 
setCurrentState(Lifecycle.@onNull State state)94     void setCurrentState(Lifecycle.@NonNull State state) {
95         mLifecycleRegistry.setCurrentState(state);
96     }
97 
handleLifecycleEvent(Lifecycle.@onNull Event event)98     void handleLifecycleEvent(Lifecycle.@NonNull Event event) {
99         mLifecycleRegistry.handleLifecycleEvent(event);
100     }
101 
102     /**
103      * {@inheritDoc}
104      *
105      * <p>The {@link Fragment#getArguments() Fragment's arguments} when this is first called will
106      * be used as the defaults to any {@link androidx.lifecycle.SavedStateHandle} passed to a
107      * view model created using this factory.</p>
108      */
109     @Override
getDefaultViewModelProviderFactory()110     public ViewModelProvider.@NonNull Factory getDefaultViewModelProviderFactory() {
111         ViewModelProvider.Factory currentFactory =
112                 mFragment.getDefaultViewModelProviderFactory();
113 
114         if (!currentFactory.equals(mFragment.mDefaultFactory)) {
115             mDefaultFactory = currentFactory;
116             return currentFactory;
117         }
118 
119         if (mDefaultFactory == null) {
120             Application application = null;
121             Context appContext = mFragment.requireContext().getApplicationContext();
122             while (appContext instanceof ContextWrapper) {
123                 if (appContext instanceof Application) {
124                     application = (Application) appContext;
125                     break;
126                 }
127                 appContext = ((ContextWrapper) appContext).getBaseContext();
128             }
129 
130             mDefaultFactory = new SavedStateViewModelFactory(
131                     application,
132                     mFragment,
133                     mFragment.getArguments());
134         }
135 
136         return mDefaultFactory;
137     }
138 
139     @Override
140     @CallSuper
getDefaultViewModelCreationExtras()141     public @NonNull CreationExtras getDefaultViewModelCreationExtras() {
142         Application application = null;
143         Context appContext = mFragment.requireContext().getApplicationContext();
144         while (appContext instanceof ContextWrapper) {
145             if (appContext instanceof Application) {
146                 application = (Application) appContext;
147                 break;
148             }
149             appContext = ((ContextWrapper) appContext).getBaseContext();
150         }
151         MutableCreationExtras extras = new MutableCreationExtras();
152         if (application != null) {
153             extras.set(ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY, application);
154         }
155         extras.set(SavedStateHandleSupport.SAVED_STATE_REGISTRY_OWNER_KEY, mFragment);
156         extras.set(SavedStateHandleSupport.VIEW_MODEL_STORE_OWNER_KEY, this);
157         if (mFragment.getArguments() != null) {
158             extras.set(SavedStateHandleSupport.DEFAULT_ARGS_KEY, mFragment.getArguments());
159         }
160         return extras;
161     }
162 
163     @Override
getSavedStateRegistry()164     public @NonNull SavedStateRegistry getSavedStateRegistry() {
165         initialize();
166         return mSavedStateRegistryController.getSavedStateRegistry();
167     }
168 
performRestore(@ullable Bundle savedState)169     void performRestore(@Nullable Bundle savedState) {
170         mSavedStateRegistryController.performRestore(savedState);
171     }
172 
performSave(@onNull Bundle outBundle)173     void performSave(@NonNull Bundle outBundle) {
174         mSavedStateRegistryController.performSave(outBundle);
175     }
176 }
177