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.util.kotlin 18 19 import android.view.View 20 import androidx.lifecycle.Lifecycle 21 import androidx.lifecycle.repeatOnLifecycle 22 import com.android.systemui.dagger.SysUISingleton 23 import com.android.systemui.dagger.qualifiers.Application 24 import com.android.systemui.lifecycle.repeatWhenAttached 25 import java.util.function.Consumer 26 import javax.inject.Inject 27 import kotlin.coroutines.CoroutineContext 28 import kotlin.coroutines.EmptyCoroutineContext 29 import kotlinx.coroutines.CoroutineScope 30 import kotlinx.coroutines.Job 31 import kotlinx.coroutines.flow.Flow 32 import kotlinx.coroutines.flow.combine 33 import kotlinx.coroutines.launch 34 35 /** A class allowing Java classes to collect on Kotlin flows. */ 36 @SysUISingleton 37 class JavaAdapter 38 @Inject 39 constructor( 40 @Application private val scope: CoroutineScope, 41 ) { 42 /** 43 * Collect information for the given [flow], calling [consumer] for each emitted event. 44 * 45 * Important: This will immediately start collection and *never* stop it. This should only be 46 * used by classes that *need* to always be collecting a value and processing it. Whenever 47 * possible, please use [collectFlow] instead; that method will stop the collection when a view 48 * has disappeared, which will ensure that we don't perform unnecessary work. 49 * 50 * Do *not* call this method in a class's constructor. Instead, call it in 51 * [com.android.systemui.CoreStartable.start] or similar method. 52 */ 53 fun <T> alwaysCollectFlow( 54 flow: Flow<T>, 55 consumer: Consumer<T>, 56 ): Job { 57 return scope.launch { flow.collect { consumer.accept(it) } } 58 } 59 } 60 61 /** 62 * Collect information for the given [flow], calling [consumer] for each emitted event. Defaults to 63 * [LifeCycle.State.CREATED] to better align with legacy ViewController usage of attaching listeners 64 * during onViewAttached() and removing during onViewRemoved() 65 */ 66 @JvmOverloads 67 fun <T> collectFlow( 68 view: View, 69 flow: Flow<T>, 70 consumer: Consumer<T>, 71 coroutineContext: CoroutineContext = EmptyCoroutineContext, 72 state: Lifecycle.State = Lifecycle.State.CREATED, 73 ) { 74 view.repeatWhenAttached(coroutineContext) { 75 repeatOnLifecycle(state) { flow.collect { consumer.accept(it) } } 76 } 77 } 78 79 fun <A, B, R> combineFlows(flow1: Flow<A>, flow2: Flow<B>, bifunction: (A, B) -> R): Flow<R> { 80 return combine(flow1, flow2, bifunction) 81 } 82