diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp index d172006d986d8..3cf5bc1bf13a9 100644 --- a/packages/SystemUI/shared/Android.bp +++ b/packages/SystemUI/shared/Android.bp @@ -49,9 +49,12 @@ android_library { "PluginCoreLib", "androidx.dynamicanimation_dynamicanimation", "androidx.concurrent_concurrent-futures", + "dagger2", + "jsr330", ], java_version: "1.8", min_sdk_version: "current", + plugins: ["dagger2-compiler"], } java_library { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Main.java b/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Main.java similarity index 100% rename from packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Main.java rename to packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Main.java diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt new file mode 100644 index 0000000000000..ac62cf9f9d5bb --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.unfold + +import android.content.ContentResolver +import android.content.Context +import android.hardware.SensorManager +import android.hardware.devicestate.DeviceStateManager +import android.os.Handler +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.unfold.config.UnfoldTransitionConfig +import com.android.systemui.unfold.updates.screen.ScreenStatusProvider +import com.android.systemui.unfold.util.UnfoldTransitionATracePrefix +import dagger.BindsInstance +import dagger.Component +import java.util.Optional +import java.util.concurrent.Executor +import javax.inject.Singleton + +/** + * Provides [UnfoldTransitionProgressProvider]. The [Optional] is empty when the transition + * animation is disabled. + * + * This component is meant to be used for places that don't use dagger. By providing those + * parameters to the factory, all dagger objects are correctly instantiated. See + * [createUnfoldTransitionProgressProvider] for an example. + */ +@Singleton +@Component(modules = [UnfoldSharedModule::class]) +internal interface UnfoldSharedComponent { + + @Component.Factory + interface Factory { + fun create( + @BindsInstance context: Context, + @BindsInstance config: UnfoldTransitionConfig, + @BindsInstance screenStatusProvider: ScreenStatusProvider, + @BindsInstance deviceStateManager: DeviceStateManager, + @BindsInstance sensorManager: SensorManager, + @BindsInstance @Main handler: Handler, + @BindsInstance @Main executor: Executor, + @BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String, + @BindsInstance contentResolver: ContentResolver = context.contentResolver + ): UnfoldSharedComponent + } + + val unfoldTransitionProvider: Optional +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedModule.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedModule.kt new file mode 100644 index 0000000000000..23e4c97fc2713 --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedModule.kt @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.unfold + +import android.hardware.SensorManager +import com.android.systemui.unfold.config.UnfoldTransitionConfig +import com.android.systemui.unfold.progress.FixedTimingTransitionProgressProvider +import com.android.systemui.unfold.progress.PhysicsBasedUnfoldTransitionProgressProvider +import com.android.systemui.unfold.updates.DeviceFoldStateProvider +import com.android.systemui.unfold.updates.FoldStateProvider +import com.android.systemui.unfold.updates.hinge.EmptyHingeAngleProvider +import com.android.systemui.unfold.updates.hinge.HingeAngleProvider +import com.android.systemui.unfold.updates.hinge.HingeSensorAngleProvider +import com.android.systemui.unfold.util.ATraceLoggerTransitionProgressListener +import com.android.systemui.unfold.util.ScaleAwareTransitionProgressProvider +import dagger.Module +import dagger.Provides +import java.util.Optional +import javax.inject.Singleton + +@Module +class UnfoldSharedModule { + @Provides + @Singleton + fun unfoldTransitionProgressProvider( + config: UnfoldTransitionConfig, + scaleAwareProviderFactory: ScaleAwareTransitionProgressProvider.Factory, + tracingListener: ATraceLoggerTransitionProgressListener, + foldStateProvider: FoldStateProvider + ): Optional = + if (!config.isEnabled) { + Optional.empty() + } else { + val baseProgressProvider = + if (config.isHingeAngleEnabled) { + PhysicsBasedUnfoldTransitionProgressProvider(foldStateProvider) + } else { + FixedTimingTransitionProgressProvider(foldStateProvider) + } + Optional.of( + scaleAwareProviderFactory.wrap(baseProgressProvider).apply { + // Always present callback that logs animation beginning and end. + addCallback(tracingListener) + }) + } + + @Provides + @Singleton + fun provideFoldStateProvider( + deviceFoldStateProvider: DeviceFoldStateProvider + ): FoldStateProvider = deviceFoldStateProvider + + @Provides + fun hingeAngleProvider( + config: UnfoldTransitionConfig, + sensorManager: SensorManager + ): HingeAngleProvider = + if (config.isHingeAngleEnabled) { + HingeSensorAngleProvider(sensorManager) + } else { + EmptyHingeAngleProvider + } +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt index 953b0e0183069..d5d636208747c 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt @@ -23,22 +23,16 @@ import android.hardware.devicestate.DeviceStateManager import android.os.Handler import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig import com.android.systemui.unfold.config.UnfoldTransitionConfig -import com.android.systemui.unfold.progress.FixedTimingTransitionProgressProvider -import com.android.systemui.unfold.progress.PhysicsBasedUnfoldTransitionProgressProvider -import com.android.systemui.unfold.updates.DeviceFoldStateProvider -import com.android.systemui.unfold.updates.FoldStateProvider -import com.android.systemui.unfold.updates.hinge.EmptyHingeAngleProvider -import com.android.systemui.unfold.updates.hinge.HingeSensorAngleProvider import com.android.systemui.unfold.updates.screen.ScreenStatusProvider -import com.android.systemui.unfold.util.ATraceLoggerTransitionProgressListener -import com.android.systemui.unfold.util.ScaleAwareTransitionProgressProvider import java.util.concurrent.Executor /** * Factory for [UnfoldTransitionProgressProvider]. * - * This is needed as Launcher has to create the object manually. Sysui create it using dagger (see - * [UnfoldTransitionModule]). + * This is needed as Launcher has to create the object manually. If dagger is available, this object + * is provided in [UnfoldSharedModule]. + * + * This should **never** be called from sysui, as the object is already provided in that process. */ fun createUnfoldTransitionProgressProvider( context: Context, @@ -49,62 +43,21 @@ fun createUnfoldTransitionProgressProvider( mainHandler: Handler, mainExecutor: Executor, tracingTagPrefix: String -): UnfoldTransitionProgressProvider { - - if (!config.isEnabled) { - throw IllegalStateException( - "Trying to create " + - "UnfoldTransitionProgressProvider when the transition is disabled") - } - - val foldStateProvider = - createFoldStateProvider( +): UnfoldTransitionProgressProvider = + DaggerUnfoldSharedComponent.factory() + .create( context, config, screenStatusProvider, deviceStateManager, sensorManager, mainHandler, - mainExecutor) - - val unfoldTransitionProgressProvider = - if (config.isHingeAngleEnabled) { - PhysicsBasedUnfoldTransitionProgressProvider(foldStateProvider) - } else { - FixedTimingTransitionProgressProvider(foldStateProvider) - } - - return ScaleAwareTransitionProgressProvider( - unfoldTransitionProgressProvider, context.contentResolver) - .apply { - // Always present callback that logs animation beginning and end. - addCallback(ATraceLoggerTransitionProgressListener(tracingTagPrefix)) - } -} - -fun createFoldStateProvider( - context: Context, - config: UnfoldTransitionConfig, - screenStatusProvider: ScreenStatusProvider, - deviceStateManager: DeviceStateManager, - sensorManager: SensorManager, - mainHandler: Handler, - mainExecutor: Executor -): FoldStateProvider { - val hingeAngleProvider = - if (config.isHingeAngleEnabled) { - HingeSensorAngleProvider(sensorManager) - } else { - EmptyHingeAngleProvider() - } - - return DeviceFoldStateProvider( - context, - hingeAngleProvider, - screenStatusProvider, - deviceStateManager, - mainExecutor, - mainHandler) -} + mainExecutor, + tracingTagPrefix) + .unfoldTransitionProvider + .orElse(null) + ?: throw IllegalStateException( + "Trying to create " + + "UnfoldTransitionProgressProvider when the transition is disabled") fun createConfig(context: Context): UnfoldTransitionConfig = ResourceUnfoldTransitionConfig(context) diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt index cd1ea215ccdd5..204ae09b48525 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt @@ -22,6 +22,7 @@ import android.os.Handler import android.util.Log import androidx.annotation.VisibleForTesting import androidx.core.util.Consumer +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener import com.android.systemui.unfold.updates.hinge.FULLY_CLOSED_DEGREES @@ -29,14 +30,17 @@ import com.android.systemui.unfold.updates.hinge.FULLY_OPEN_DEGREES import com.android.systemui.unfold.updates.hinge.HingeAngleProvider import com.android.systemui.unfold.updates.screen.ScreenStatusProvider import java.util.concurrent.Executor +import javax.inject.Inject -class DeviceFoldStateProvider( +class DeviceFoldStateProvider +@Inject +constructor( context: Context, private val hingeAngleProvider: HingeAngleProvider, private val screenStatusProvider: ScreenStatusProvider, private val deviceStateManager: DeviceStateManager, - private val mainExecutor: Executor, - private val handler: Handler + @Main private val mainExecutor: Executor, + @Main private val handler: Handler ) : FoldStateProvider { private val outputListeners: MutableList = mutableListOf() diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt index 9b58b1fcad467..4ca1a531fc259 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt @@ -2,7 +2,7 @@ package com.android.systemui.unfold.updates.hinge import androidx.core.util.Consumer -internal class EmptyHingeAngleProvider : HingeAngleProvider { +internal object EmptyHingeAngleProvider : HingeAngleProvider { override fun start() { } diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressListener.kt similarity index 76% rename from packages/SystemUI/shared/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressProvider.kt rename to packages/SystemUI/shared/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressListener.kt index f3eeb3210ece7..1574c8d37ab11 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressProvider.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ATraceLoggerTransitionProgressListener.kt @@ -2,6 +2,8 @@ package com.android.systemui.unfold.util import android.os.Trace import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener +import javax.inject.Inject +import javax.inject.Qualifier /** * Listener that logs start and end of the fold-unfold transition. @@ -9,7 +11,10 @@ import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionPr * [tracePrefix] arg helps in differentiating those. Currently, this is expected to be logged twice * for each fold/unfold: in (1) systemui and (2) launcher process. */ -class ATraceLoggerTransitionProgressListener(tracePrefix: String) : TransitionProgressListener { +class ATraceLoggerTransitionProgressListener +@Inject +internal constructor(@UnfoldTransitionATracePrefix tracePrefix: String) : + TransitionProgressListener { private val traceName = "$tracePrefix#$UNFOLD_TRANSITION_TRACE_NAME" @@ -27,3 +32,5 @@ class ATraceLoggerTransitionProgressListener(tracePrefix: String) : TransitionPr } private const val UNFOLD_TRANSITION_TRACE_NAME = "FoldUnfoldTransitionInProgress" + +@Qualifier annotation class UnfoldTransitionATracePrefix diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt index df9078a15520e..ee79b8761059a 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt @@ -6,15 +6,20 @@ import android.database.ContentObserver import android.provider.Settings import com.android.systemui.unfold.UnfoldTransitionProgressProvider import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject /** Wraps [UnfoldTransitionProgressProvider] to disable transitions when animations are disabled. */ -class ScaleAwareTransitionProgressProvider( - unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider, +class ScaleAwareTransitionProgressProvider +@AssistedInject +constructor( + @Assisted progressProviderToWrap: UnfoldTransitionProgressProvider, private val contentResolver: ContentResolver ) : UnfoldTransitionProgressProvider { private val scopedUnfoldTransitionProgressProvider = - ScopedUnfoldTransitionProgressProvider(unfoldTransitionProgressProvider) + ScopedUnfoldTransitionProgressProvider(progressProviderToWrap) private val animatorDurationScaleObserver = object : ContentObserver(null) { override fun onChange(selfChange: Boolean) { @@ -47,4 +52,11 @@ class ScaleAwareTransitionProgressProvider( contentResolver.unregisterContentObserver(animatorDurationScaleObserver) scopedUnfoldTransitionProgressProvider.destroy() } + + @AssistedFactory + interface Factory { + fun wrap( + progressProvider: UnfoldTransitionProgressProvider + ): ScaleAwareTransitionProgressProvider + } } diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt index c2fd34c719a0d..178d01477a098 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt @@ -17,87 +17,38 @@ package com.android.systemui.unfold import android.content.Context -import android.hardware.SensorManager -import android.hardware.devicestate.DeviceStateManager -import android.os.Handler import android.view.IWindowManager -import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.LifecycleScreenStatusProvider import com.android.systemui.unfold.config.UnfoldTransitionConfig import com.android.systemui.unfold.updates.FoldStateProvider +import com.android.systemui.unfold.updates.screen.ScreenStatusProvider import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider +import com.android.systemui.unfold.util.UnfoldTransitionATracePrefix import com.android.systemui.util.time.SystemClockImpl import com.android.wm.shell.unfold.ShellUnfoldProgressProvider import dagger.Lazy import dagger.Module import dagger.Provides import java.util.Optional -import java.util.concurrent.Executor import javax.inject.Named import javax.inject.Singleton -@Module +@Module(includes = [UnfoldSharedModule::class]) class UnfoldTransitionModule { - @Provides - @Singleton - fun provideUnfoldTransitionProgressProvider( - context: Context, - config: UnfoldTransitionConfig, - screenStatusProvider: Lazy, - deviceStateManager: DeviceStateManager, - sensorManager: SensorManager, - @Main executor: Executor, - @Main handler: Handler - ): Optional = - if (config.isEnabled) { - Optional.of( - createUnfoldTransitionProgressProvider( - context, - config, - screenStatusProvider.get(), - deviceStateManager, - sensorManager, - handler, - executor, - tracingTagPrefix = "systemui")) - } else { - Optional.empty() - } - - @Provides - @Singleton - fun provideFoldStateProvider( - context: Context, - config: UnfoldTransitionConfig, - screenStatusProvider: Lazy, - deviceStateManager: DeviceStateManager, - sensorManager: SensorManager, - @Main executor: Executor, - @Main handler: Handler - ): Optional = - if (!config.isHingeAngleEnabled) { - Optional.empty() - } else { - Optional.of( - createFoldStateProvider( - context, - config, - screenStatusProvider.get(), - deviceStateManager, - sensorManager, - handler, - executor)) - } + @Provides @UnfoldTransitionATracePrefix fun tracingTagPrefix() = "systemui" @Provides @Singleton fun providesFoldStateLoggingProvider( - optionalFoldStateProvider: Optional + config: UnfoldTransitionConfig, + foldStateProvider: Lazy ): Optional = - optionalFoldStateProvider.map { foldStateProvider -> - FoldStateLoggingProviderImpl(foldStateProvider, SystemClockImpl()) + if (config.isHingeAngleEnabled) { + Optional.of(FoldStateLoggingProviderImpl(foldStateProvider.get(), SystemClockImpl())) + } else { + Optional.empty() } @Provides @@ -144,6 +95,9 @@ class UnfoldTransitionModule { } else { ShellUnfoldProgressProvider.NO_PROVIDER } + + @Provides + fun screenStatusProvider(impl: LifecycleScreenStatusProvider): ScreenStatusProvider = impl } const val UNFOLD_STATUS_BAR = "unfold_status_bar"