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