1 /* 2 * Copyright (C) 2020 The Dagger Authors. 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 dagger.hilt.android.internal.managers; 18 19 import android.content.Context; 20 import androidx.activity.ComponentActivity; 21 import androidx.annotation.NonNull; 22 import androidx.annotation.Nullable; 23 import androidx.lifecycle.ViewModel; 24 import androidx.lifecycle.ViewModelProvider; 25 import androidx.lifecycle.ViewModelStoreOwner; 26 import androidx.lifecycle.viewmodel.CreationExtras; 27 import dagger.Module; 28 import dagger.Provides; 29 import dagger.hilt.EntryPoint; 30 import dagger.hilt.EntryPoints; 31 import dagger.hilt.InstallIn; 32 import dagger.hilt.android.ActivityRetainedLifecycle; 33 import dagger.hilt.android.EntryPointAccessors; 34 import dagger.hilt.android.components.ActivityRetainedComponent; 35 import dagger.hilt.android.internal.builders.ActivityRetainedComponentBuilder; 36 import dagger.hilt.android.internal.lifecycle.RetainedLifecycleImpl; 37 import dagger.hilt.android.scopes.ActivityRetainedScoped; 38 import dagger.hilt.components.SingletonComponent; 39 import dagger.hilt.internal.GeneratedComponentManager; 40 41 /** A manager for the creation of components that survives activity configuration changes. */ 42 final class ActivityRetainedComponentManager 43 implements GeneratedComponentManager<ActivityRetainedComponent> { 44 45 /** Entry point for {@link ActivityRetainedComponentBuilder}. */ 46 @EntryPoint 47 @InstallIn(SingletonComponent.class) 48 public interface ActivityRetainedComponentBuilderEntryPoint { retainedComponentBuilder()49 ActivityRetainedComponentBuilder retainedComponentBuilder(); 50 } 51 52 /** Entry point for {@link ActivityRetainedLifecycle}. */ 53 @EntryPoint 54 @InstallIn(ActivityRetainedComponent.class) 55 public interface ActivityRetainedLifecycleEntryPoint { getActivityRetainedLifecycle()56 ActivityRetainedLifecycle getActivityRetainedLifecycle(); 57 } 58 59 static final class ActivityRetainedComponentViewModel extends ViewModel { 60 private final ActivityRetainedComponent component; 61 private final SavedStateHandleHolder savedStateHandleHolder; 62 ActivityRetainedComponentViewModel( ActivityRetainedComponent component, SavedStateHandleHolder savedStateHandleHolder)63 ActivityRetainedComponentViewModel( 64 ActivityRetainedComponent component, SavedStateHandleHolder savedStateHandleHolder) { 65 this.component = component; 66 this.savedStateHandleHolder = savedStateHandleHolder; 67 } 68 getComponent()69 ActivityRetainedComponent getComponent() { 70 return component; 71 } 72 getSavedStateHandleHolder()73 SavedStateHandleHolder getSavedStateHandleHolder() { 74 return savedStateHandleHolder; 75 } 76 77 @Override onCleared()78 protected void onCleared() { 79 super.onCleared(); 80 ActivityRetainedLifecycle lifecycle = 81 EntryPoints.get(component, ActivityRetainedLifecycleEntryPoint.class) 82 .getActivityRetainedLifecycle(); 83 ((RetainedLifecycleImpl) lifecycle).dispatchOnCleared(); 84 } 85 } 86 87 private final ViewModelStoreOwner viewModelStoreOwner; 88 private final Context context; 89 90 @Nullable private volatile ActivityRetainedComponent component; 91 private final Object componentLock = new Object(); 92 ActivityRetainedComponentManager(ComponentActivity activity)93 ActivityRetainedComponentManager(ComponentActivity activity) { 94 this.viewModelStoreOwner = activity; 95 this.context = activity; 96 } 97 getViewModelProvider( ViewModelStoreOwner owner, Context context)98 private ViewModelProvider getViewModelProvider( 99 ViewModelStoreOwner owner, Context context) { 100 return new ViewModelProvider( 101 owner, 102 new ViewModelProvider.Factory() { 103 @NonNull 104 @Override 105 @SuppressWarnings("unchecked") 106 public <T extends ViewModel> T create( 107 @NonNull Class<T> aClass, CreationExtras creationExtras) { 108 SavedStateHandleHolder savedStateHandleHolder = 109 new SavedStateHandleHolder(creationExtras); 110 ActivityRetainedComponent component = 111 EntryPointAccessors.fromApplication( 112 context, ActivityRetainedComponentBuilderEntryPoint.class) 113 .retainedComponentBuilder() 114 .savedStateHandleHolder(savedStateHandleHolder) 115 .build(); 116 return (T) new ActivityRetainedComponentViewModel(component, savedStateHandleHolder); 117 } 118 }); 119 } 120 121 @Override 122 public ActivityRetainedComponent generatedComponent() { 123 // TODO(bcorso): don't need the component lock since the component is stored in ViewModel 124 // which does its own locking 125 if (component == null) { 126 synchronized (componentLock) { 127 if (component == null) { 128 component = createComponent(); 129 } 130 } 131 } 132 return component; 133 } 134 135 public SavedStateHandleHolder getSavedStateHandleHolder() { 136 return getViewModelProvider(viewModelStoreOwner, context) 137 .get(ActivityRetainedComponentViewModel.class) 138 .getSavedStateHandleHolder(); 139 } 140 141 private ActivityRetainedComponent createComponent() { 142 return getViewModelProvider(viewModelStoreOwner, context) 143 .get(ActivityRetainedComponentViewModel.class) 144 .getComponent(); 145 } 146 147 @Module 148 @InstallIn(ActivityRetainedComponent.class) 149 abstract static class LifecycleModule { 150 @Provides 151 @ActivityRetainedScoped 152 static ActivityRetainedLifecycle provideActivityRetainedLifecycle() { 153 return new RetainedLifecycleImpl(); 154 } 155 } 156 } 157