1 /* 2 * Copyright (C) 2021 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.systemui.unfold.util 17 18 import com.android.systemui.unfold.UnfoldTransitionProgressProvider 19 import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener 20 21 /** 22 * Manages progress listeners that can have smaller lifespan than the unfold animation. 23 * 24 * Allows to limit getting transition updates to only when 25 * [ScopedUnfoldTransitionProgressProvider.setReadyToHandleTransition] is called with 26 * readyToHandleTransition = true 27 * 28 * If the transition has already started by the moment when the clients are ready to play the 29 * transition then it will report transition started callback and current animation progress. 30 */ 31 open class ScopedUnfoldTransitionProgressProvider 32 @JvmOverloads 33 constructor(source: UnfoldTransitionProgressProvider? = null) : 34 UnfoldTransitionProgressProvider, TransitionProgressListener { 35 36 private var source: UnfoldTransitionProgressProvider? = null 37 38 private val listeners: MutableList<TransitionProgressListener> = mutableListOf() 39 40 private var isReadyToHandleTransition = false 41 private var isTransitionRunning = false 42 private var lastTransitionProgress = PROGRESS_UNSET 43 44 init { 45 setSourceProvider(source) 46 } 47 /** 48 * Sets the source for the unfold transition progress updates. Replaces current provider if it 49 * is already set 50 * 51 * @param provider transition provider that emits transition progress updates 52 */ 53 fun setSourceProvider(provider: UnfoldTransitionProgressProvider?) { 54 source?.removeCallback(this) 55 56 if (provider != null) { 57 source = provider 58 provider.addCallback(this) 59 } else { 60 source = null 61 } 62 } 63 64 /** 65 * Allows to notify this provide whether the listeners can play the transition or not. 66 * 67 * Call this method with readyToHandleTransition = true when all listeners are ready to consume 68 * the transition progress events. 69 * 70 * Call it with readyToHandleTransition = false when listeners can't process the events. 71 */ 72 fun setReadyToHandleTransition(isReadyToHandleTransition: Boolean) { 73 if (isTransitionRunning) { 74 if (isReadyToHandleTransition) { 75 listeners.forEach { it.onTransitionStarted() } 76 if (lastTransitionProgress != PROGRESS_UNSET) { 77 listeners.forEach { it.onTransitionProgress(lastTransitionProgress) } 78 } 79 } else { 80 isTransitionRunning = false 81 listeners.forEach { it.onTransitionFinished() } 82 } 83 } 84 this.isReadyToHandleTransition = isReadyToHandleTransition 85 } 86 87 override fun addCallback(listener: TransitionProgressListener) { 88 listeners += listener 89 } 90 91 override fun removeCallback(listener: TransitionProgressListener) { 92 listeners -= listener 93 } 94 95 override fun destroy() { 96 source?.removeCallback(this) 97 source?.destroy() 98 } 99 100 override fun onTransitionStarted() { 101 isTransitionRunning = true 102 if (isReadyToHandleTransition) { 103 listeners.forEach { it.onTransitionStarted() } 104 } 105 } 106 107 override fun onTransitionProgress(progress: Float) { 108 if (isReadyToHandleTransition) { 109 listeners.forEach { it.onTransitionProgress(progress) } 110 } 111 lastTransitionProgress = progress 112 } 113 114 override fun onTransitionFinishing() { 115 if (isReadyToHandleTransition) { 116 listeners.forEach { it.onTransitionFinishing() } 117 } 118 } 119 120 override fun onTransitionFinished() { 121 if (isReadyToHandleTransition) { 122 listeners.forEach { it.onTransitionFinished() } 123 } 124 isTransitionRunning = false 125 lastTransitionProgress = PROGRESS_UNSET 126 } 127 128 companion object { 129 private const val PROGRESS_UNSET = -1f 130 } 131 } 132