1 /* 2 * Copyright (C) 2022 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.systemui.unfold 18 19 import android.os.Handler 20 import com.android.systemui.unfold.config.UnfoldTransitionConfig 21 import com.android.systemui.unfold.dagger.UnfoldBg 22 import com.android.systemui.unfold.dagger.UnfoldBgProgressFlag 23 import com.android.systemui.unfold.dagger.UnfoldMain 24 import com.android.systemui.unfold.progress.FixedTimingTransitionProgressProvider 25 import com.android.systemui.unfold.progress.MainThreadUnfoldTransitionProgressProvider 26 import com.android.systemui.unfold.progress.PhysicsBasedUnfoldTransitionProgressProvider 27 import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder 28 import com.android.systemui.unfold.updates.DeviceFoldStateProvider 29 import com.android.systemui.unfold.updates.FoldStateProvider 30 import com.android.systemui.unfold.updates.RotationChangeProvider 31 import com.android.systemui.unfold.updates.hinge.EmptyHingeAngleProvider 32 import com.android.systemui.unfold.updates.hinge.HingeAngleProvider 33 import com.android.systemui.unfold.updates.hinge.HingeSensorAngleProvider 34 import com.android.systemui.unfold.util.ATraceLoggerTransitionProgressListener 35 import com.android.systemui.unfold.util.ScaleAwareTransitionProgressProvider 36 import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityManager 37 import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityManagerImpl 38 import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityProvider 39 import dagger.BindsOptionalOf 40 import dagger.Module 41 import dagger.Provides 42 import java.util.Optional 43 import javax.inject.Provider 44 import javax.inject.Singleton 45 import kotlin.jvm.optionals.getOrDefault 46 47 @Module( 48 includes = 49 [ 50 UnfoldFlagsModule::class, 51 UnfoldSharedInternalModule::class, 52 UnfoldRotationProviderInternalModule::class, 53 HingeAngleProviderInternalModule::class, 54 FoldStateProviderModule::class, 55 ] 56 ) 57 class UnfoldSharedModule { 58 @Provides 59 @Singleton unfoldKeyguardVisibilityProvidernull60 fun unfoldKeyguardVisibilityProvider( 61 impl: UnfoldKeyguardVisibilityManagerImpl 62 ): UnfoldKeyguardVisibilityProvider = impl 63 64 @Provides 65 @Singleton 66 fun unfoldKeyguardVisibilityManager( 67 impl: UnfoldKeyguardVisibilityManagerImpl 68 ): UnfoldKeyguardVisibilityManager = impl 69 } 70 71 @Module 72 abstract class UnfoldFlagsModule { 73 /** 74 * Users of the library can bind this boolean to notify whether the progress should be 75 * calculated only in the background (and the main thread provider is generated by posting the 76 * background events in the main handler). 77 */ 78 @BindsOptionalOf @UnfoldBgProgressFlag abstract fun unfoldBgProgressFlag(): Boolean 79 } 80 81 /** 82 * Needed as methods inside must be public, but their parameters can be internal (and, a public 83 * method can't have internal parameters). Making the module internal and included in a public one 84 * fixes the issue. 85 */ 86 @Module 87 internal class UnfoldSharedInternalModule { 88 @Provides 89 @Singleton unfoldTransitionProgressProvidernull90 fun unfoldTransitionProgressProvider( 91 config: UnfoldTransitionConfig, 92 scaleAwareProviderFactory: ScaleAwareTransitionProgressProvider.Factory, 93 tracingListener: ATraceLoggerTransitionProgressListener.Factory, 94 physicsBasedUnfoldTransitionProgressProvider: 95 PhysicsBasedUnfoldTransitionProgressProvider.Factory, 96 fixedTimingTransitionProgressProvider: Provider<FixedTimingTransitionProgressProvider>, 97 foldStateProvider: FoldStateProvider, 98 @UnfoldMain mainHandler: Handler, 99 mainThreadUnfoldTransitionProgressProviderFactory: 100 MainThreadUnfoldTransitionProgressProvider.Factory, 101 @UnfoldBg bgProvider: Provider<Optional<UnfoldTransitionProgressProvider>>, 102 @UnfoldBgProgressFlag unfoldBgProgressFlag: Optional<Boolean>, 103 ): Optional<UnfoldTransitionProgressProvider> { 104 if (unfoldBgProgressFlag.getOrDefault(false)) { 105 // In this case, we wrap the background progress provider 106 val mainThreadProvider: Optional<UnfoldTransitionProgressProvider> = 107 bgProvider.get().map { 108 mainThreadUnfoldTransitionProgressProviderFactory.create(it) 109 } 110 mainThreadProvider.ifPresent { 111 it.addCallback(tracingListener.create("MainThreadFromBgProgress")) 112 } 113 return mainThreadProvider 114 } else { 115 // TODO(b/277879146): Remove this once unfold_animation_background_progress is launched. 116 return createOptionalUnfoldTransitionProgressProvider( 117 config = config, 118 scaleAwareProviderFactory = scaleAwareProviderFactory, 119 tracingListener = tracingListener.create("MainThread"), 120 physicsBasedUnfoldTransitionProgressProvider = 121 physicsBasedUnfoldTransitionProgressProvider, 122 fixedTimingTransitionProgressProvider = fixedTimingTransitionProgressProvider, 123 foldStateProvider = foldStateProvider, 124 progressHandler = mainHandler, 125 ) 126 } 127 } 128 129 @Provides 130 @Singleton 131 @UnfoldBg unfoldBgTransitionProgressProvidernull132 fun unfoldBgTransitionProgressProvider( 133 config: UnfoldTransitionConfig, 134 scaleAwareProviderFactory: ScaleAwareTransitionProgressProvider.Factory, 135 tracingListener: ATraceLoggerTransitionProgressListener.Factory, 136 physicsBasedUnfoldTransitionProgressProvider: 137 PhysicsBasedUnfoldTransitionProgressProvider.Factory, 138 fixedTimingTransitionProgressProvider: Provider<FixedTimingTransitionProgressProvider>, 139 @UnfoldBg bgFoldStateProvider: FoldStateProvider, 140 @UnfoldBg bgHandler: Handler, 141 ): Optional<UnfoldTransitionProgressProvider> { 142 return createOptionalUnfoldTransitionProgressProvider( 143 config = config, 144 scaleAwareProviderFactory = scaleAwareProviderFactory, 145 tracingListener = tracingListener.create("BgThread"), 146 physicsBasedUnfoldTransitionProgressProvider = 147 physicsBasedUnfoldTransitionProgressProvider, 148 fixedTimingTransitionProgressProvider = fixedTimingTransitionProgressProvider, 149 foldStateProvider = bgFoldStateProvider, 150 progressHandler = bgHandler, 151 ) 152 } 153 createOptionalUnfoldTransitionProgressProvidernull154 private fun createOptionalUnfoldTransitionProgressProvider( 155 config: UnfoldTransitionConfig, 156 scaleAwareProviderFactory: ScaleAwareTransitionProgressProvider.Factory, 157 tracingListener: ATraceLoggerTransitionProgressListener, 158 physicsBasedUnfoldTransitionProgressProvider: 159 PhysicsBasedUnfoldTransitionProgressProvider.Factory, 160 fixedTimingTransitionProgressProvider: Provider<FixedTimingTransitionProgressProvider>, 161 foldStateProvider: FoldStateProvider, 162 progressHandler: Handler, 163 ): Optional<UnfoldTransitionProgressProvider> { 164 if (!config.isEnabled) { 165 return Optional.empty() 166 } 167 val baseProgressProvider = 168 if (config.isHingeAngleEnabled) { 169 physicsBasedUnfoldTransitionProgressProvider.create( 170 foldStateProvider, 171 progressHandler 172 ) 173 } else { 174 fixedTimingTransitionProgressProvider.get() 175 } 176 177 return Optional.of( 178 scaleAwareProviderFactory.wrap(baseProgressProvider).apply { 179 // Always present callback that logs animation beginning and end. 180 addCallback(tracingListener) 181 } 182 ) 183 } 184 185 @Provides 186 @Singleton provideProgressForwardernull187 fun provideProgressForwarder( 188 config: UnfoldTransitionConfig, 189 progressForwarder: Provider<UnfoldTransitionProgressForwarder> 190 ): Optional<UnfoldTransitionProgressForwarder> { 191 if (!config.isEnabled) { 192 return Optional.empty() 193 } 194 return Optional.of(progressForwarder.get()) 195 } 196 } 197 198 /** 199 * Provides [FoldStateProvider]. The [UnfoldBg] annotated binding sends progress in the [UnfoldBg] 200 * handler. 201 */ 202 @Module 203 internal class FoldStateProviderModule { 204 @Provides 205 @Singleton provideFoldStateProvidernull206 fun provideFoldStateProvider( 207 factory: DeviceFoldStateProvider.Factory, 208 @UnfoldMain hingeAngleProvider: HingeAngleProvider, 209 @UnfoldMain rotationChangeProvider: RotationChangeProvider, 210 @UnfoldMain mainHandler: Handler, 211 ): FoldStateProvider = 212 factory.create( 213 hingeAngleProvider, 214 rotationChangeProvider, 215 progressHandler = mainHandler 216 ) 217 218 @Provides 219 @Singleton 220 @UnfoldBg 221 fun provideBgFoldStateProvider( 222 factory: DeviceFoldStateProvider.Factory, 223 @UnfoldBg hingeAngleProvider: HingeAngleProvider, 224 @UnfoldBg rotationChangeProvider: RotationChangeProvider, 225 @UnfoldBg bgHandler: Handler, 226 ): FoldStateProvider = 227 factory.create( 228 hingeAngleProvider, 229 rotationChangeProvider, 230 progressHandler = bgHandler 231 ) 232 } 233 234 /** Provides bindings for both [UnfoldMain] and [UnfoldBg] [HingeAngleProvider]. */ 235 @Module 236 internal class HingeAngleProviderInternalModule { 237 @Provides 238 @UnfoldMain 239 fun hingeAngleProvider( 240 config: UnfoldTransitionConfig, 241 @UnfoldMain handler: Handler, 242 hingeAngleSensorProvider: HingeSensorAngleProvider.Factory 243 ): HingeAngleProvider { 244 return if (config.isHingeAngleEnabled) { 245 hingeAngleSensorProvider.create(handler) 246 } else { 247 EmptyHingeAngleProvider 248 } 249 } 250 251 @Provides 252 @UnfoldBg 253 fun hingeAngleProviderBg( 254 config: UnfoldTransitionConfig, 255 @UnfoldBg handler: Handler, 256 hingeAngleSensorProvider: HingeSensorAngleProvider.Factory 257 ): HingeAngleProvider { 258 return if (config.isHingeAngleEnabled) { 259 hingeAngleSensorProvider.create(handler) 260 } else { 261 EmptyHingeAngleProvider 262 } 263 } 264 } 265 266 @Module 267 internal class UnfoldRotationProviderInternalModule { 268 @Provides 269 @Singleton 270 @UnfoldMain provideRotationChangeProvidernull271 fun provideRotationChangeProvider( 272 rotationChangeProviderFactory: RotationChangeProvider.Factory, 273 @UnfoldMain callbackHandler: Handler, 274 ): RotationChangeProvider { 275 return rotationChangeProviderFactory.create(callbackHandler) 276 } 277 278 @Provides 279 @Singleton 280 @UnfoldBg provideBgRotationChangeProvidernull281 fun provideBgRotationChangeProvider( 282 rotationChangeProviderFactory: RotationChangeProvider.Factory, 283 @UnfoldBg callbackHandler: Handler, 284 ): RotationChangeProvider { 285 // For UnfoldBg RotationChangeProvider we use bgHandler as callbackHandler 286 return rotationChangeProviderFactory.create(callbackHandler) 287 } 288 } 289