1 /* <lambda>null2 * Copyright (C) 2023 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 package com.android.dream.lowlight 17 18 import android.animation.Animator 19 import android.animation.AnimatorListenerAdapter 20 import com.android.dream.lowlight.util.suspendCoroutineWithTimeout 21 import javax.inject.Inject 22 import javax.inject.Singleton 23 import kotlin.coroutines.resume 24 import kotlin.time.Duration 25 26 /** 27 * Helper class that allows listening and running animations before entering or exiting low light. 28 */ 29 @Singleton 30 class LowLightTransitionCoordinator @Inject constructor() { 31 /** 32 * Listener that is notified before low light entry. 33 */ 34 interface LowLightEnterListener { 35 /** 36 * Callback that is notified before the device enters low light. 37 * 38 * @return an optional animator that will be waited upon before entering low light. 39 */ 40 fun onBeforeEnterLowLight(): Animator? 41 } 42 43 /** 44 * Listener that is notified before low light exit. 45 */ 46 interface LowLightExitListener { 47 /** 48 * Callback that is notified before the device exits low light. 49 * 50 * @return an optional animator that will be waited upon before exiting low light. 51 */ 52 fun onBeforeExitLowLight(): Animator? 53 } 54 55 private var mLowLightEnterListener: LowLightEnterListener? = null 56 private var mLowLightExitListener: LowLightExitListener? = null 57 58 /** 59 * Sets the listener for the low light enter event. 60 * 61 * Only one listener can be set at a time. This method will overwrite any previously set 62 * listener. Null can be used to unset the listener. 63 */ 64 fun setLowLightEnterListener(lowLightEnterListener: LowLightEnterListener?) { 65 mLowLightEnterListener = lowLightEnterListener 66 } 67 68 /** 69 * Sets the listener for the low light exit event. 70 * 71 * Only one listener can be set at a time. This method will overwrite any previously set 72 * listener. Null can be used to unset the listener. 73 */ 74 fun setLowLightExitListener(lowLightExitListener: LowLightExitListener?) { 75 mLowLightExitListener = lowLightExitListener 76 } 77 78 /** 79 * Notifies listeners that the device is about to enter or exit low light, and waits for the 80 * animation to complete. If this function is cancelled, the animation is also cancelled. 81 * 82 * @param timeout the maximum duration to wait for the transition animation. If the animation 83 * does not complete within this time period, a 84 * @param entering true if listeners should be notified before entering low light, false if this 85 * is notifying before exiting. 86 */ 87 suspend fun waitForLowLightTransitionAnimation(timeout: Duration, entering: Boolean) = 88 suspendCoroutineWithTimeout(timeout) { continuation -> 89 var animator: Animator? = null 90 if (entering && mLowLightEnterListener != null) { 91 animator = mLowLightEnterListener!!.onBeforeEnterLowLight() 92 } else if (!entering && mLowLightExitListener != null) { 93 animator = mLowLightExitListener!!.onBeforeExitLowLight() 94 } 95 96 if (animator == null) { 97 continuation.resume(Unit) 98 return@suspendCoroutineWithTimeout 99 } 100 101 // If the listener returned an animator to indicate it was running an animation, run the 102 // callback after the animation completes, otherwise call the callback directly. 103 val listener = object : AnimatorListenerAdapter() { 104 override fun onAnimationEnd(animator: Animator) { 105 continuation.resume(Unit) 106 } 107 108 override fun onAnimationCancel(animation: Animator) { 109 continuation.cancel() 110 } 111 } 112 animator.addListener(listener) 113 } 114 } 115