Loading libs/dream/lowlight/Android.bp +6 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ filegroup { name: "low_light_dream_lib-sources", srcs: [ "src/**/*.java", "src/**/*.kt", ], path: "src", } Loading @@ -37,10 +38,15 @@ android_library { resource_dirs: [ "res", ], libs: [ "kotlin-annotations", ], static_libs: [ "androidx.arch.core_core-runtime", "dagger2", "jsr330", "kotlinx-coroutines-android", "kotlinx-coroutines-core", ], manifest: "AndroidManifest.xml", plugins: ["dagger2-compiler"], Loading libs/dream/lowlight/res/values/config.xml +3 −0 Original line number Diff line number Diff line Loading @@ -17,4 +17,7 @@ <resources> <!-- The dream component used when the device is low light environment. --> <string translatable="false" name="config_lowLightDreamComponent"/> <!-- The max number of milliseconds to wait for the low light transition before setting the system dream component --> <integer name="config_lowLightTransitionTimeoutMs">2000</integer> </resources> libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.javadeleted 100644 → 0 +0 −122 Original line number Diff line number Diff line /* * 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.dream.lowlight; import static com.android.dream.lowlight.dagger.LowLightDreamModule.LOW_LIGHT_DREAM_COMPONENT; import android.annotation.IntDef; import android.annotation.RequiresPermission; import android.app.DreamManager; import android.content.ComponentName; import android.util.Log; import androidx.annotation.Nullable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import javax.inject.Inject; import javax.inject.Named; /** * Maintains the ambient light mode of the environment the device is in, and sets a low light dream * component, if present, as the system dream when the ambient light mode is low light. * * @hide */ public final class LowLightDreamManager { private static final String TAG = "LowLightDreamManager"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); /** * @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "AMBIENT_LIGHT_MODE_" }, value = { AMBIENT_LIGHT_MODE_UNKNOWN, AMBIENT_LIGHT_MODE_REGULAR, AMBIENT_LIGHT_MODE_LOW_LIGHT }) public @interface AmbientLightMode {} /** * Constant for ambient light mode being unknown. * @hide */ public static final int AMBIENT_LIGHT_MODE_UNKNOWN = 0; /** * Constant for ambient light mode being regular / bright. * @hide */ public static final int AMBIENT_LIGHT_MODE_REGULAR = 1; /** * Constant for ambient light mode being low light / dim. * @hide */ public static final int AMBIENT_LIGHT_MODE_LOW_LIGHT = 2; private final DreamManager mDreamManager; private final LowLightTransitionCoordinator mLowLightTransitionCoordinator; @Nullable private final ComponentName mLowLightDreamComponent; private int mAmbientLightMode = AMBIENT_LIGHT_MODE_UNKNOWN; @Inject public LowLightDreamManager( DreamManager dreamManager, LowLightTransitionCoordinator lowLightTransitionCoordinator, @Named(LOW_LIGHT_DREAM_COMPONENT) @Nullable ComponentName lowLightDreamComponent) { mDreamManager = dreamManager; mLowLightTransitionCoordinator = lowLightTransitionCoordinator; mLowLightDreamComponent = lowLightDreamComponent; } /** * Sets the current ambient light mode. * @hide */ @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void setAmbientLightMode(@AmbientLightMode int ambientLightMode) { if (mLowLightDreamComponent == null) { if (DEBUG) { Log.d(TAG, "ignore ambient light mode change because low light dream component " + "is empty"); } return; } if (mAmbientLightMode == ambientLightMode) { return; } if (DEBUG) { Log.d(TAG, "ambient light mode changed from " + mAmbientLightMode + " to " + ambientLightMode); } mAmbientLightMode = ambientLightMode; boolean shouldEnterLowLight = mAmbientLightMode == AMBIENT_LIGHT_MODE_LOW_LIGHT; mLowLightTransitionCoordinator.notifyBeforeLowLightTransition(shouldEnterLowLight, () -> mDreamManager.setSystemDreamComponent( shouldEnterLowLight ? mLowLightDreamComponent : null)); } } libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.kt 0 → 100644 +138 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.dream.lowlight import android.Manifest import android.annotation.IntDef import android.annotation.RequiresPermission import android.app.DreamManager import android.content.ComponentName import android.util.Log import com.android.dream.lowlight.dagger.LowLightDreamModule import com.android.dream.lowlight.dagger.qualifiers.Application import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.launch import javax.inject.Inject import javax.inject.Named import kotlin.time.DurationUnit import kotlin.time.toDuration /** * Maintains the ambient light mode of the environment the device is in, and sets a low light dream * component, if present, as the system dream when the ambient light mode is low light. * * @hide */ class LowLightDreamManager @Inject constructor( @Application private val coroutineScope: CoroutineScope, private val dreamManager: DreamManager, private val lowLightTransitionCoordinator: LowLightTransitionCoordinator, @param:Named(LowLightDreamModule.LOW_LIGHT_DREAM_COMPONENT) private val lowLightDreamComponent: ComponentName?, @param:Named(LowLightDreamModule.LOW_LIGHT_TRANSITION_TIMEOUT_MS) private val lowLightTransitionTimeoutMs: Long ) { /** * @hide */ @Retention(AnnotationRetention.SOURCE) @IntDef( prefix = ["AMBIENT_LIGHT_MODE_"], value = [ AMBIENT_LIGHT_MODE_UNKNOWN, AMBIENT_LIGHT_MODE_REGULAR, AMBIENT_LIGHT_MODE_LOW_LIGHT ] ) annotation class AmbientLightMode private var mTransitionJob: Job? = null private var mAmbientLightMode = AMBIENT_LIGHT_MODE_UNKNOWN private val mLowLightTransitionTimeout = lowLightTransitionTimeoutMs.toDuration(DurationUnit.MILLISECONDS) /** * Sets the current ambient light mode. * * @hide */ @RequiresPermission(Manifest.permission.WRITE_DREAM_STATE) fun setAmbientLightMode(@AmbientLightMode ambientLightMode: Int) { if (lowLightDreamComponent == null) { if (DEBUG) { Log.d( TAG, "ignore ambient light mode change because low light dream component is empty" ) } return } if (mAmbientLightMode == ambientLightMode) { return } if (DEBUG) { Log.d( TAG, "ambient light mode changed from $mAmbientLightMode to $ambientLightMode" ) } mAmbientLightMode = ambientLightMode val shouldEnterLowLight = mAmbientLightMode == AMBIENT_LIGHT_MODE_LOW_LIGHT // Cancel any previous transitions mTransitionJob?.cancel() mTransitionJob = coroutineScope.launch { try { lowLightTransitionCoordinator.waitForLowLightTransitionAnimation( timeout = mLowLightTransitionTimeout, entering = shouldEnterLowLight ) } catch (ex: TimeoutCancellationException) { Log.e(TAG, "timed out while waiting for low light animation", ex) } dreamManager.setSystemDreamComponent( if (shouldEnterLowLight) lowLightDreamComponent else null ) } } companion object { private const val TAG = "LowLightDreamManager" private val DEBUG = Log.isLoggable(TAG, Log.DEBUG) /** * Constant for ambient light mode being unknown. * * @hide */ const val AMBIENT_LIGHT_MODE_UNKNOWN = 0 /** * Constant for ambient light mode being regular / bright. * * @hide */ const val AMBIENT_LIGHT_MODE_REGULAR = 1 /** * Constant for ambient light mode being low light / dim. * * @hide */ const val AMBIENT_LIGHT_MODE_LOW_LIGHT = 2 } } libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.java→libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt +118 −0 Original line number Diff line number Diff line Loading @@ -13,51 +13,47 @@ * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.dream.lowlight package com.android.dream.lowlight; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.Nullable; import javax.inject.Inject; import javax.inject.Singleton; import android.animation.Animator import android.animation.AnimatorListenerAdapter import com.android.dream.lowlight.util.suspendCoroutineWithTimeout import javax.inject.Inject import javax.inject.Singleton import kotlin.coroutines.resume import kotlin.time.Duration /** * Helper class that allows listening and running animations before entering or exiting low light. */ @Singleton public class LowLightTransitionCoordinator { class LowLightTransitionCoordinator @Inject constructor() { /** * Listener that is notified before low light entry. */ public interface LowLightEnterListener { interface LowLightEnterListener { /** * Callback that is notified before the device enters low light. * * @return an optional animator that will be waited upon before entering low light. */ Animator onBeforeEnterLowLight(); fun onBeforeEnterLowLight(): Animator? } /** * Listener that is notified before low light exit. */ public interface LowLightExitListener { interface LowLightExitListener { /** * Callback that is notified before the device exits low light. * * @return an optional animator that will be waited upon before exiting low light. */ Animator onBeforeExitLowLight(); fun onBeforeExitLowLight(): Animator? } private LowLightEnterListener mLowLightEnterListener; private LowLightExitListener mLowLightExitListener; @Inject public LowLightTransitionCoordinator() { } private var mLowLightEnterListener: LowLightEnterListener? = null private var mLowLightExitListener: LowLightExitListener? = null /** * Sets the listener for the low light enter event. Loading @@ -65,8 +61,8 @@ public class LowLightTransitionCoordinator { * Only one listener can be set at a time. This method will overwrite any previously set * listener. Null can be used to unset the listener. */ public void setLowLightEnterListener(@Nullable LowLightEnterListener lowLightEnterListener) { mLowLightEnterListener = lowLightEnterListener; fun setLowLightEnterListener(lowLightEnterListener: LowLightEnterListener?) { mLowLightEnterListener = lowLightEnterListener } /** Loading @@ -75,37 +71,48 @@ public class LowLightTransitionCoordinator { * Only one listener can be set at a time. This method will overwrite any previously set * listener. Null can be used to unset the listener. */ public void setLowLightExitListener(@Nullable LowLightExitListener lowLightExitListener) { mLowLightExitListener = lowLightExitListener; fun setLowLightExitListener(lowLightExitListener: LowLightExitListener?) { mLowLightExitListener = lowLightExitListener } /** * Notifies listeners that the device is about to enter or exit low light. * Notifies listeners that the device is about to enter or exit low light, and waits for the * animation to complete. If this function is cancelled, the animation is also cancelled. * * @param timeout the maximum duration to wait for the transition animation. If the animation * does not complete within this time period, a * @param entering true if listeners should be notified before entering low light, false if this * is notifying before exiting. * @param callback callback that will be run after listeners complete. */ void notifyBeforeLowLightTransition(boolean entering, Runnable callback) { Animator animator = null; suspend fun waitForLowLightTransitionAnimation(timeout: Duration, entering: Boolean) = suspendCoroutineWithTimeout(timeout) { continuation -> var animator: Animator? = null if (entering && mLowLightEnterListener != null) { animator = mLowLightEnterListener.onBeforeEnterLowLight(); animator = mLowLightEnterListener!!.onBeforeEnterLowLight() } else if (!entering && mLowLightExitListener != null) { animator = mLowLightExitListener.onBeforeExitLowLight(); animator = mLowLightExitListener!!.onBeforeExitLowLight() } if (animator == null) { continuation.resume(Unit) return@suspendCoroutineWithTimeout } // If the listener returned an animator to indicate it was running an animation, run the // callback after the animation completes, otherwise call the callback directly. if (animator != null) { animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animator) { callback.run(); val listener = object : AnimatorListenerAdapter() { override fun onAnimationEnd(animator: Animator) { continuation.resume(Unit) } override fun onAnimationCancel(animation: Animator) { continuation.cancel() } } }); } else { callback.run(); animator.addListener(listener) continuation.invokeOnCancellation { animator.removeListener(listener) animator.cancel() } } } Loading
libs/dream/lowlight/Android.bp +6 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ filegroup { name: "low_light_dream_lib-sources", srcs: [ "src/**/*.java", "src/**/*.kt", ], path: "src", } Loading @@ -37,10 +38,15 @@ android_library { resource_dirs: [ "res", ], libs: [ "kotlin-annotations", ], static_libs: [ "androidx.arch.core_core-runtime", "dagger2", "jsr330", "kotlinx-coroutines-android", "kotlinx-coroutines-core", ], manifest: "AndroidManifest.xml", plugins: ["dagger2-compiler"], Loading
libs/dream/lowlight/res/values/config.xml +3 −0 Original line number Diff line number Diff line Loading @@ -17,4 +17,7 @@ <resources> <!-- The dream component used when the device is low light environment. --> <string translatable="false" name="config_lowLightDreamComponent"/> <!-- The max number of milliseconds to wait for the low light transition before setting the system dream component --> <integer name="config_lowLightTransitionTimeoutMs">2000</integer> </resources>
libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.javadeleted 100644 → 0 +0 −122 Original line number Diff line number Diff line /* * 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.dream.lowlight; import static com.android.dream.lowlight.dagger.LowLightDreamModule.LOW_LIGHT_DREAM_COMPONENT; import android.annotation.IntDef; import android.annotation.RequiresPermission; import android.app.DreamManager; import android.content.ComponentName; import android.util.Log; import androidx.annotation.Nullable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import javax.inject.Inject; import javax.inject.Named; /** * Maintains the ambient light mode of the environment the device is in, and sets a low light dream * component, if present, as the system dream when the ambient light mode is low light. * * @hide */ public final class LowLightDreamManager { private static final String TAG = "LowLightDreamManager"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); /** * @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "AMBIENT_LIGHT_MODE_" }, value = { AMBIENT_LIGHT_MODE_UNKNOWN, AMBIENT_LIGHT_MODE_REGULAR, AMBIENT_LIGHT_MODE_LOW_LIGHT }) public @interface AmbientLightMode {} /** * Constant for ambient light mode being unknown. * @hide */ public static final int AMBIENT_LIGHT_MODE_UNKNOWN = 0; /** * Constant for ambient light mode being regular / bright. * @hide */ public static final int AMBIENT_LIGHT_MODE_REGULAR = 1; /** * Constant for ambient light mode being low light / dim. * @hide */ public static final int AMBIENT_LIGHT_MODE_LOW_LIGHT = 2; private final DreamManager mDreamManager; private final LowLightTransitionCoordinator mLowLightTransitionCoordinator; @Nullable private final ComponentName mLowLightDreamComponent; private int mAmbientLightMode = AMBIENT_LIGHT_MODE_UNKNOWN; @Inject public LowLightDreamManager( DreamManager dreamManager, LowLightTransitionCoordinator lowLightTransitionCoordinator, @Named(LOW_LIGHT_DREAM_COMPONENT) @Nullable ComponentName lowLightDreamComponent) { mDreamManager = dreamManager; mLowLightTransitionCoordinator = lowLightTransitionCoordinator; mLowLightDreamComponent = lowLightDreamComponent; } /** * Sets the current ambient light mode. * @hide */ @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void setAmbientLightMode(@AmbientLightMode int ambientLightMode) { if (mLowLightDreamComponent == null) { if (DEBUG) { Log.d(TAG, "ignore ambient light mode change because low light dream component " + "is empty"); } return; } if (mAmbientLightMode == ambientLightMode) { return; } if (DEBUG) { Log.d(TAG, "ambient light mode changed from " + mAmbientLightMode + " to " + ambientLightMode); } mAmbientLightMode = ambientLightMode; boolean shouldEnterLowLight = mAmbientLightMode == AMBIENT_LIGHT_MODE_LOW_LIGHT; mLowLightTransitionCoordinator.notifyBeforeLowLightTransition(shouldEnterLowLight, () -> mDreamManager.setSystemDreamComponent( shouldEnterLowLight ? mLowLightDreamComponent : null)); } }
libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.kt 0 → 100644 +138 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.dream.lowlight import android.Manifest import android.annotation.IntDef import android.annotation.RequiresPermission import android.app.DreamManager import android.content.ComponentName import android.util.Log import com.android.dream.lowlight.dagger.LowLightDreamModule import com.android.dream.lowlight.dagger.qualifiers.Application import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.launch import javax.inject.Inject import javax.inject.Named import kotlin.time.DurationUnit import kotlin.time.toDuration /** * Maintains the ambient light mode of the environment the device is in, and sets a low light dream * component, if present, as the system dream when the ambient light mode is low light. * * @hide */ class LowLightDreamManager @Inject constructor( @Application private val coroutineScope: CoroutineScope, private val dreamManager: DreamManager, private val lowLightTransitionCoordinator: LowLightTransitionCoordinator, @param:Named(LowLightDreamModule.LOW_LIGHT_DREAM_COMPONENT) private val lowLightDreamComponent: ComponentName?, @param:Named(LowLightDreamModule.LOW_LIGHT_TRANSITION_TIMEOUT_MS) private val lowLightTransitionTimeoutMs: Long ) { /** * @hide */ @Retention(AnnotationRetention.SOURCE) @IntDef( prefix = ["AMBIENT_LIGHT_MODE_"], value = [ AMBIENT_LIGHT_MODE_UNKNOWN, AMBIENT_LIGHT_MODE_REGULAR, AMBIENT_LIGHT_MODE_LOW_LIGHT ] ) annotation class AmbientLightMode private var mTransitionJob: Job? = null private var mAmbientLightMode = AMBIENT_LIGHT_MODE_UNKNOWN private val mLowLightTransitionTimeout = lowLightTransitionTimeoutMs.toDuration(DurationUnit.MILLISECONDS) /** * Sets the current ambient light mode. * * @hide */ @RequiresPermission(Manifest.permission.WRITE_DREAM_STATE) fun setAmbientLightMode(@AmbientLightMode ambientLightMode: Int) { if (lowLightDreamComponent == null) { if (DEBUG) { Log.d( TAG, "ignore ambient light mode change because low light dream component is empty" ) } return } if (mAmbientLightMode == ambientLightMode) { return } if (DEBUG) { Log.d( TAG, "ambient light mode changed from $mAmbientLightMode to $ambientLightMode" ) } mAmbientLightMode = ambientLightMode val shouldEnterLowLight = mAmbientLightMode == AMBIENT_LIGHT_MODE_LOW_LIGHT // Cancel any previous transitions mTransitionJob?.cancel() mTransitionJob = coroutineScope.launch { try { lowLightTransitionCoordinator.waitForLowLightTransitionAnimation( timeout = mLowLightTransitionTimeout, entering = shouldEnterLowLight ) } catch (ex: TimeoutCancellationException) { Log.e(TAG, "timed out while waiting for low light animation", ex) } dreamManager.setSystemDreamComponent( if (shouldEnterLowLight) lowLightDreamComponent else null ) } } companion object { private const val TAG = "LowLightDreamManager" private val DEBUG = Log.isLoggable(TAG, Log.DEBUG) /** * Constant for ambient light mode being unknown. * * @hide */ const val AMBIENT_LIGHT_MODE_UNKNOWN = 0 /** * Constant for ambient light mode being regular / bright. * * @hide */ const val AMBIENT_LIGHT_MODE_REGULAR = 1 /** * Constant for ambient light mode being low light / dim. * * @hide */ const val AMBIENT_LIGHT_MODE_LOW_LIGHT = 2 } }
libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.java→libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt +118 −0 Original line number Diff line number Diff line Loading @@ -13,51 +13,47 @@ * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.dream.lowlight package com.android.dream.lowlight; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.Nullable; import javax.inject.Inject; import javax.inject.Singleton; import android.animation.Animator import android.animation.AnimatorListenerAdapter import com.android.dream.lowlight.util.suspendCoroutineWithTimeout import javax.inject.Inject import javax.inject.Singleton import kotlin.coroutines.resume import kotlin.time.Duration /** * Helper class that allows listening and running animations before entering or exiting low light. */ @Singleton public class LowLightTransitionCoordinator { class LowLightTransitionCoordinator @Inject constructor() { /** * Listener that is notified before low light entry. */ public interface LowLightEnterListener { interface LowLightEnterListener { /** * Callback that is notified before the device enters low light. * * @return an optional animator that will be waited upon before entering low light. */ Animator onBeforeEnterLowLight(); fun onBeforeEnterLowLight(): Animator? } /** * Listener that is notified before low light exit. */ public interface LowLightExitListener { interface LowLightExitListener { /** * Callback that is notified before the device exits low light. * * @return an optional animator that will be waited upon before exiting low light. */ Animator onBeforeExitLowLight(); fun onBeforeExitLowLight(): Animator? } private LowLightEnterListener mLowLightEnterListener; private LowLightExitListener mLowLightExitListener; @Inject public LowLightTransitionCoordinator() { } private var mLowLightEnterListener: LowLightEnterListener? = null private var mLowLightExitListener: LowLightExitListener? = null /** * Sets the listener for the low light enter event. Loading @@ -65,8 +61,8 @@ public class LowLightTransitionCoordinator { * Only one listener can be set at a time. This method will overwrite any previously set * listener. Null can be used to unset the listener. */ public void setLowLightEnterListener(@Nullable LowLightEnterListener lowLightEnterListener) { mLowLightEnterListener = lowLightEnterListener; fun setLowLightEnterListener(lowLightEnterListener: LowLightEnterListener?) { mLowLightEnterListener = lowLightEnterListener } /** Loading @@ -75,37 +71,48 @@ public class LowLightTransitionCoordinator { * Only one listener can be set at a time. This method will overwrite any previously set * listener. Null can be used to unset the listener. */ public void setLowLightExitListener(@Nullable LowLightExitListener lowLightExitListener) { mLowLightExitListener = lowLightExitListener; fun setLowLightExitListener(lowLightExitListener: LowLightExitListener?) { mLowLightExitListener = lowLightExitListener } /** * Notifies listeners that the device is about to enter or exit low light. * Notifies listeners that the device is about to enter or exit low light, and waits for the * animation to complete. If this function is cancelled, the animation is also cancelled. * * @param timeout the maximum duration to wait for the transition animation. If the animation * does not complete within this time period, a * @param entering true if listeners should be notified before entering low light, false if this * is notifying before exiting. * @param callback callback that will be run after listeners complete. */ void notifyBeforeLowLightTransition(boolean entering, Runnable callback) { Animator animator = null; suspend fun waitForLowLightTransitionAnimation(timeout: Duration, entering: Boolean) = suspendCoroutineWithTimeout(timeout) { continuation -> var animator: Animator? = null if (entering && mLowLightEnterListener != null) { animator = mLowLightEnterListener.onBeforeEnterLowLight(); animator = mLowLightEnterListener!!.onBeforeEnterLowLight() } else if (!entering && mLowLightExitListener != null) { animator = mLowLightExitListener.onBeforeExitLowLight(); animator = mLowLightExitListener!!.onBeforeExitLowLight() } if (animator == null) { continuation.resume(Unit) return@suspendCoroutineWithTimeout } // If the listener returned an animator to indicate it was running an animation, run the // callback after the animation completes, otherwise call the callback directly. if (animator != null) { animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animator) { callback.run(); val listener = object : AnimatorListenerAdapter() { override fun onAnimationEnd(animator: Animator) { continuation.resume(Unit) } override fun onAnimationCancel(animation: Animator) { continuation.cancel() } } }); } else { callback.run(); animator.addListener(listener) continuation.invokeOnCancellation { animator.removeListener(listener) animator.cancel() } } }