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