1 /*
<lambda>null2  * Copyright 2024 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 androidx.camera.core.impl.utils
18 
19 import androidx.annotation.MainThread
20 import androidx.arch.core.util.Function
21 import androidx.camera.core.impl.utils.Threads.runOnMain
22 import androidx.lifecycle.LiveData
23 import androidx.lifecycle.MediatorLiveData
24 import androidx.lifecycle.Observer
25 
26 public object LiveDataUtil {
27     /**
28      * Returns a [LiveData] mapped from the input [LiveData] by applying {@code mapFunction} to each
29      * value set on {@code source}.
30      *
31      * Similar to [androidx.lifecycle.Transformations.map], but it can ensure [getValue] returns
32      * mapped value without the need to have active observers.
33      */
34     @MainThread
35     @JvmStatic
36     public fun <I, O> map(source: LiveData<I>, mapFunction: Function<I, O>): LiveData<O> {
37         val result = MappingRedirectableLiveData<I, O>(mapFunction.apply(source.value), mapFunction)
38         result.redirectTo(source)
39         return result
40     }
41 }
42 
43 /**
44  * A [LiveData] which can be redirected to a source [LiveData] in order to use the source data as
45  * its own.
46  *
47  * This `LiveData` is considered as the destination `LiveData` while the source `LiveData` is the
48  * one this redirects to. Whenever source `LiveData` gets updated with a value, this `LiveData` is
49  * also updated with that value.
50  *
51  * @param T The type of both the source `LiveData` and this `LiveData`.
52  * @property initialValue The initial value that is returned if no redirection is set yet.
53  * @see MappingRedirectableLiveData
54  */
55 public class RedirectableLiveData<T>(private val initialValue: T) :
<lambda>null56     MappingRedirectableLiveData<T, T>(initialValue, { it })
57 
58 /**
59  * A [LiveData] which can be redirected to a source [LiveData] in order to map the source data as
60  * its own data.
61  *
62  * This `LiveData` is considered as the destination `LiveData` while the source `LiveData` is the
63  * one this redirects to. Whenever source `LiveData` gets updated with a value, this `LiveData` is
64  * also updated with a mapped equivalent of that value.
65  *
66  * @param I The type of the source `LiveData`.
67  * @param O The type of the destination `LiveData`.
68  * @property initialValue The initial value that is returned if no redirection is set yet.
69  * @property mapFunction The function that maps source data.
70  * @see redirectTo
71  */
72 public open class MappingRedirectableLiveData<I, O>(
73     private val initialValue: O,
74     private val mapFunction: Function<I, O>
75 ) : MediatorLiveData<O>() {
76     private var liveDataSource: LiveData<I>? = null
77 
78     /**
79      * Redirects to a source [LiveData] whose value is mapped to this `LiveData`.
80      *
81      * After this function is invoked, the data of this `LiveData` will depend on the source live
82      * data with [mapFunction] invoked.
83      *
84      * @param liveDataSource The source `LiveData`.
85      */
redirectTonull86     public fun redirectTo(liveDataSource: LiveData<I>) {
87         if (this.liveDataSource != null) {
88             super.removeSource(this.liveDataSource!!)
89         }
90         this.liveDataSource = liveDataSource
91         runOnMain {
92             // addSource should be invoked in main thread.
93             super.addSource(liveDataSource) { value: I -> this.value = mapFunction.apply(value) }
94         }
95     }
96 
addSourcenull97     override fun <S> addSource(source: LiveData<S>, onChanged: Observer<in S>) {
98         throw UnsupportedOperationException()
99     }
100 
101     // Overrides getValue() to reflect the correct value from source. This is required to ensure
102     // getValue() is correct when observe() or observeForever() is not called.
103     /**
104      * Gets the value of this [LiveData] based on the provided redirection and mapping.
105      *
106      * If no redirection has been set yet, the [initialValue] property is returned.
107      *
108      * @see redirectTo
109      * @see MediatorLiveData.getValue
110      */
getValuenull111     override fun getValue(): O? {
112         // Returns initial value if source is not set.
113         val liveDataSource = this.liveDataSource // snapshot for non-null smart casting
114         if (liveDataSource == null) {
115             return initialValue
116         }
117         return mapFunction.apply(liveDataSource.value)
118     }
119 }
120