1 /*
2  * Copyright 2018 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.car.arch.common;
18 
19 import static java.util.Objects.requireNonNull;
20 
21 import androidx.annotation.NonNull;
22 import androidx.annotation.Nullable;
23 import androidx.arch.core.util.Function;
24 import androidx.core.util.Pair;
25 import androidx.lifecycle.LiveData;
26 import androidx.lifecycle.MediatorLiveData;
27 import androidx.lifecycle.MutableLiveData;
28 import androidx.lifecycle.Observer;
29 import androidx.lifecycle.Transformations;
30 
31 import java.util.Objects;
32 import java.util.function.BiConsumer;
33 import java.util.function.BiFunction;
34 import java.util.function.BiPredicate;
35 import java.util.function.Predicate;
36 
37 /**
38  * Utility methods for using {@link LiveData}. In general for Boolean operations, {@code null} is
39  * treated as an "unknown" value, and operations may use short-circuit evaluation to determine the
40  * result. LiveData may be in an uninitialized state where observers are not called when registered
41  * (e.g. a {@link MutableLiveData} where {@link MutableLiveData#setValue(Object)} has not yet been
42  * called). If a Boolean operation receives an uninitialized LiveData as either of its parameters,
43  * the result will also be in an uninitialized state.
44  */
45 @SuppressWarnings({"unused", "WeakerAccess"})
46 public class LiveDataFunctions {
47 
LiveDataFunctions()48     private LiveDataFunctions() {
49     }
50 
51     private static volatile LiveData<?> sNullLiveData;
52     private static volatile LiveData<Boolean> sTrueLiveData;
53     private static volatile LiveData<Boolean> sFalseLiveData;
54 
55     /**
56      * Returns a LiveData that always emits {@code null}. This is different than an uninitialized
57      * LiveData in that observers will be called (with {@code null}) when registered.
58      */
nullLiveData()59     public static <T> LiveData<T> nullLiveData() {
60         if (sNullLiveData == null) {
61             sNullLiveData = dataOf(null);
62         }
63         // null can fit any generic type
64         // noinspection unchecked
65         return (LiveData<T>) sNullLiveData;
66     }
67 
68     /** Returns a LiveData that always emits {@code true}. */
trueLiveData()69     public static LiveData<Boolean> trueLiveData() {
70         if (sTrueLiveData == null) {
71             sTrueLiveData = dataOf(true);
72         }
73         return sTrueLiveData;
74     }
75 
76     /** Returns a LiveData that always emits {@code false}. */
falseLiveData()77     public static LiveData<Boolean> falseLiveData() {
78         if (sFalseLiveData == null) {
79             sFalseLiveData = dataOf(false);
80         }
81         return sFalseLiveData;
82     }
83 
84     /** Returns a LiveData that is initialized with {@code value}. */
dataOf(@ullable T value)85     public static <T> MutableLiveData<T> dataOf(@Nullable T value) {
86         MutableLiveData<T> data = new MutableLiveData<>();
87         data.setValue(value);
88         return data;
89     }
90 
91     /**
92      * Returns a LiveData that emits the opposite of {@code source} (or {@code null} if {@code
93      * source} emits {@code null})
94      */
not(@onNull LiveData<Boolean> source)95     public static LiveData<Boolean> not(@NonNull LiveData<Boolean> source) {
96         return Transformations.map(source, bool -> bool == null ? null : !bool);
97     }
98 
99     /**
100      * Returns a LiveData that emits {@code true} iff {@code source} emits {@code null}. Otherwise
101      * emits {@code false}
102      */
emitsNull(@onNull LiveData<?> source)103     public static LiveData<Boolean> emitsNull(@NonNull LiveData<?> source) {
104         return Transformations.map(source, Objects::isNull);
105     }
106 
107     /**
108      * Returns a LiveData that emits the same value as {@code source}, but only notifies its
109      * observers when the new value is distinct ({@link Objects#equals(Object, Object)}
110      */
distinct(@onNull LiveData<T> source)111     public static <T> LiveData<T> distinct(@NonNull LiveData<T> source) {
112         return distinct(source, Objects::equals);
113     }
114 
115     /**
116      * Returns a LiveData that emits the same value as {@code source}, but only notifies its
117      * observers when the new value is distinct ({@code areEqual} returns {@code false})
118      */
distinct(@onNull LiveData<T> source, @NonNull BiPredicate<T, T> areEqual)119     public static <T> LiveData<T> distinct(@NonNull LiveData<T> source,
120             @NonNull BiPredicate<T, T> areEqual) {
121         return new MediatorLiveData<T>() {
122             private boolean mInitialized = false;
123 
124             {
125                 addSource(source, value -> {
126                     if (!mInitialized || !areEqual.test(value, getValue())) {
127                         mInitialized = true;
128                         setValue(value);
129                     }
130                 });
131             }
132         };
133     }
134 
135     /**
136      * Create a LiveData that doesn't change when {@code isFrozen} emits {@code true}. If {@code
137      * source} has updated while the data was frozen, it will be updated to the current value once
138      * unfrozen.
139      *
140      * @param isFrozen the result will not update while this data emits {@code true}.
141      * @param source   the source data for the result.
142      * @return a LiveData that doesn't change when {@code isFrozen} emits {@code true}.
143      */
freezable(@onNull LiveData<Boolean> isFrozen, @NonNull LiveData<T> source)144     public static <T> LiveData<T> freezable(@NonNull LiveData<Boolean> isFrozen,
145             @NonNull LiveData<T> source) {
146         return new MediatorLiveData<T>() {
147 
148             private boolean mDirty = false;
149 
150             {
151                 addSource(requireNonNull(isFrozen), frozen -> {
152                     if (frozen == Boolean.FALSE && mDirty) {
153                         setValue(source.getValue());
154                         mDirty = false;
155                     }
156                 });
157                 addSource(requireNonNull(source), value -> {
158                     if (isFrozen.getValue() != Boolean.FALSE) {
159                         mDirty = true;
160                     } else {
161                         setValue(source.getValue());
162                         mDirty = false;
163                     }
164                 });
165             }
166         };
167     }
168 
169     /**
170      * Similar to {@link Transformations#map(LiveData, Function)}, but emits {@code null} when
171      * {@code source} emits {@code null}. The input to {@code func} may be treated as not nullable.
172      */
173     public static <T, R> LiveData<R> mapNonNull(@NonNull LiveData<T> source,
174             @NonNull Function<T, R> func) {
175         return mapNonNull(source, null, func);
176     }
177 
178     /**
179      * Similar to {@link Transformations#map(LiveData, Function)}, but emits {@code nullValue} when
180      * {@code source} emits {@code null}. The input to {@code func} may be treated as not nullable.
181      */
182     public static <T, R> LiveData<R> mapNonNull(@NonNull LiveData<T> source, @Nullable R nullValue,
183             @NonNull Function<T, R> func) {
184         return Transformations.map(source, value -> value == null ? nullValue : func.apply(value));
185     }
186 
187     /**
188      * Similar to {@link Transformations#switchMap(LiveData, Function)}, but emits {@code null} when
189      * {@code source} emits {@code null}. The input to {@code func} may be treated as not nullable.
190      */
191     public static <T, R> LiveData<R> switchMapNonNull(@NonNull LiveData<T> source,
192             @NonNull Function<T, LiveData<R>> func) {
193         return switchMapNonNull(source, null, func);
194     }
195 
196     /**
197      * Similar to {@link Transformations#switchMap(LiveData, Function)}, but emits {@code nullValue}
198      * when {@code source} emits {@code null}. The input to {@code func} may be treated as not
199      * nullable.
200      */
201     public static <T, R> LiveData<R> switchMapNonNull(@NonNull LiveData<T> source,
202             @Nullable R nullValue,
203             @NonNull Function<T, LiveData<R>> func) {
204         return Transformations.switchMap(source,
205                 value -> value == null ? nullLiveData() : func.apply(value));
206     }
207 
208     /**
209      * Similar to {@link Transformations#switchMap(LiveData, Function)}, but emits a FutureData,
210      * which provides a loading field for operations which may take a long time to finish.
211      *
212      * This LiveData emits values only when the loading status of the output changes. It will never
213      * emit {@code null}. If the output is loading, the emitted FutureData will have a null value
214      * for the data.
215      */
216     public static <T, R> LiveData<FutureData<R>> loadingSwitchMap(LiveData<T> trigger,
217             @NonNull Function<T, LiveData<R>> func) {
218         LiveData<R> output = Transformations.switchMap(trigger, func);
219         return new MediatorLiveData<FutureData<R>>() {
220             {
221                 addSource(trigger, data -> setValue(new FutureData<>(true, null)));
222                 addSource(output, data ->
223                         setValue(new FutureData<>(false, output.getValue())));
224             }
225         };
226     }
227 
228     /**
229      * Returns a LiveData that emits the logical AND of the two arguments. Also deals with {@code
230      * null} and uninitalized values as follows:
231      * <table>
232      * <tr>
233      * <th></th>
234      * <th>T</th>
235      * <th>F</th>
236      * <th>N</th>
237      * <th>U</th>
238      * </tr>
239      * <tr>
240      * <th>T</th>
241      * <td>T</td>
242      * <td>F</td>
243      * <td>N</td>
244      * <td>U</td>
245      * </tr>
246      * <tr>
247      * <th>F</th>
248      * <td>F</td>
249      * <td>F</td>
250      * <td>F</td>
251      * <td>U</td>
252      * </tr>
253      * <tr>
254      * <th>N</th>
255      * <td>N</td>
256      * <td>F</td>
257      * <td>N</td>
258      * <td>U</td>
259      * </tr>
260      * <tr>
261      * <th>U</th>
262      * <td>U</td>
263      * <td>U</td>
264      * <td>U</td>
265      * <td>U</td>
266      * </tr>
267      * </table>
268      * <p>
269      * T = {@code true}, F = {@code false}, N = {@code null}, U = uninitialized
270      *
271      * @return a LiveData that emits the logical AND of the two arguments
272      */
273     public static LiveData<Boolean> and(@NonNull LiveData<Boolean> x,
274             @NonNull LiveData<Boolean> y) {
275         return new BinaryOperation<>(
276                 x,
277                 y,
278                 (a, b) -> {
279                     if (a == null) {
280                         if (Boolean.FALSE.equals(b)) {
281                             return false;
282                         }
283                         return null;
284                     }
285                     if (a) {
286                         return b;
287                     }
288                     return false;
289                 });
290     }
291 
292     /**
293      * Returns a LiveData that emits the logical OR of the two arguments. Also deals with {@code
294      * null} and uninitalized values as follows:
295      * <table>
296      * <tr>
297      * <th></th>
298      * <th>T</th>
299      * <th>F</th>
300      * <th>N</th>
301      * <th>U</th>
302      * </tr>
303      * <tr>
304      * <th>T</th>
305      * <td>T</td>
306      * <td>T</td>
307      * <td>T</td>
308      * <td>U</td>
309      * </tr>
310      * <tr>
311      * <th>F</th>
312      * <td>T</td>
313      * <td>F</td>
314      * <td>N</td>
315      * <td>U</td>
316      * </tr>
317      * <tr>
318      * <th>N</th>
319      * <td>T</td>
320      * <td>N</td>
321      * <td>N</td>
322      * <td>U</td>
323      * </tr>
324      * <tr>
325      * <th>U</th>
326      * <td>U</td>
327      * <td>U</td>
328      * <td>U</td>
329      * <td>U</td>
330      * </tr>
331      * </table>
332      * <p>
333      * T = {@code true}, F = {@code false}, N = {@code null}, U = uninitialized
334      *
335      * @return a LiveData that emits the logical OR of the two arguments
336      */
337     public static LiveData<Boolean> or(@NonNull LiveData<Boolean> x, @NonNull LiveData<Boolean> y) {
338         return new BinaryOperation<>(
339                 x,
340                 y,
341                 (a, b) -> {
342                     if (a == null) {
343                         if (Boolean.TRUE.equals(b)) {
344                             return true;
345                         }
346                         return null;
347                     }
348                     if (!a) {
349                         return b;
350                     }
351                     return true;
352                 });
353     }
354 
355     /**
356      * Returns a LiveData backed by {@code value} if and only if predicate emits {@code true}. Emits
357      * {@code null} otherwise.
358      * <p>
359      * This is equivalent to {@code iff(predicate, Boolean::booleanValue, value)}
360      *
361      * @see #iff(LiveData, Predicate, LiveData)
362      */
363     public static <T> LiveData<T> iff(
364             @NonNull LiveData<Boolean> predicate, @NonNull LiveData<T> value) {
365         return iff(predicate, Boolean::booleanValue, value);
366     }
367 
368     /**
369      * Returns a LiveData backed by {@code value} if and only if the trigger emits a value that
370      * causes {@code predicate} to return {@code true}. Emits {@code null} otherwise.
371      */
372     public static <P, T> LiveData<T> iff(
373             @NonNull LiveData<P> trigger,
374             @NonNull Predicate<? super P> predicate,
375             @NonNull LiveData<T> value) {
376         return new BinaryOperation<>(
377                 trigger, value, (p, v) -> p == null || !predicate.test(p) ? null : v);
378     }
379 
380     /**
381      * Returns a LiveData that is backed by {@code trueData} when the predicate emits {@code true},
382      * {@code falseData} when the predicate emits {@code false}, and emits {@code null} when the
383      * predicate emits {@code null}.
384      * <p>
385      * This is equivalent to {@code ifThenElse(predicate, Boolean::booleanValue, trueData,
386      * falseData)}
387      *
388      * @param trueData  the LiveData whose value should be emitted when predicate is {@code true}
389      * @param falseData the LiveData whose value should be emitted when predicate is {@code false}
390      * @see #ifThenElse(LiveData, Predicate, LiveData, LiveData)
391      */
392     public static <T> LiveData<T> ifThenElse(
393             @NonNull LiveData<Boolean> predicate,
394             @NonNull LiveData<T> trueData,
395             @NonNull LiveData<T> falseData) {
396         return ifThenElse(predicate, Boolean::booleanValue, trueData, falseData);
397     }
398 
399     /**
400      * Returns a LiveData that is backed by {@code trueData} when the trigger satisfies the
401      * predicate, {@code falseData} when the trigger does not satisfy the predicate, and emits
402      * {@code null} when the trigger emits {@code null}.
403      *
404      * @param trueData  the LiveData whose value should be emitted when predicate returns {@code
405      *                  true}
406      * @param falseData the LiveData whose value should be emitted when predicate returns {@code
407      *                  false}
408      */
409     public static <P, T> LiveData<T> ifThenElse(
410             @NonNull LiveData<P> trigger,
411             @NonNull Predicate<? super P> predicate,
412             @NonNull LiveData<T> trueData,
413             @NonNull LiveData<T> falseData) {
414         return Transformations.switchMap(
415                 trigger,
416                 t -> {
417                     if (t == null) {
418                         return nullLiveData();
419                     } else {
420                         return predicate.test(t) ? trueData : falseData;
421                     }
422                 });
423     }
424 
425     /**
426      * Returns a LiveData that emits {@code trueValue} when the predicate emits {@code true}, {@code
427      * falseValue} when the predicate emits {@code false}, and emits {@code null} when the predicate
428      * emits {@code null}.
429      * <p>
430      * This is equivalent to {@code ifThenElse(predicate, Boolean::booleanValue, trueValue,
431      * falseValue)}
432      *
433      * @param trueValue  the value that should be emitted when predicate returns {@code true}
434      * @param falseValue the value that should be emitted when predicate returns {@code false}
435      * @see #ifThenElse(LiveData, Predicate, Object, Object)
436      */
437     public static <T> LiveData<T> ifThenElse(
438             @NonNull LiveData<Boolean> predicate, @Nullable T trueValue, @Nullable T falseValue) {
439         return ifThenElse(predicate, Boolean::booleanValue, trueValue, falseValue);
440     }
441 
442     /**
443      * Returns a LiveData that emits {@code trueValue} when the trigger satisfies the predicate,
444      * {@code falseValue} when the trigger does not satisfy the predicate, and emits {@code null}
445      * when the trigger emits {@code null}.
446      *
447      * @param trueValue  the value that should be emitted when predicate returns {@code true}
448      * @param falseValue the value that should be emitted when predicate returns {@code false}
449      */
450     public static <P, T> LiveData<T> ifThenElse(
451             @NonNull LiveData<P> trigger,
452             @NonNull Predicate<? super P> predicate,
453             @Nullable T trueValue,
454             @Nullable T falseValue) {
455         return Transformations.map(
456                 trigger,
457                 t -> {
458                     if (t == null) {
459                         return null;
460                     }
461                     return predicate.test(t) ? trueValue : falseValue;
462                 });
463     }
464 
465     /**
466      * Returns a LiveData that emits the value of {@code source} if it is not {@code null},
467      * otherwise it emits the value of {@code fallback}.
468      *
469      * @param source   The LiveData whose value should be emitted if not {@code null}
470      * @param fallback The LiveData whose value should be emitted when {@code source} emits {@code
471      *                 null}
472      */
473     public static <T> LiveData<T> coalesceNull(@NonNull LiveData<T> source,
474             @NonNull LiveData<T> fallback) {
475         return new BinaryOperation<>(source, fallback, true, false,
476                 (sourceValue, fallbackValue) -> sourceValue == null ? fallbackValue : sourceValue);
477     }
478 
479     /**
480      * Returns a LiveData that emits the value of {@code source} if it is not {@code null},
481      * otherwise it emits {@code fallback}.
482      *
483      * @param source   The LiveData whose value should be emitted if not {@code null}
484      * @param fallback The value that should be emitted when {@code source} emits {@code null}
485      */
486     public static <T> LiveData<T> coalesceNull(@NonNull LiveData<T> source, T fallback) {
487         return Transformations.map(source, value -> value == null ? fallback : value);
488     }
489 
490     /**
491      * Returns a LiveData that emits a Pair containing the values of the two parameter LiveDatas. If
492      * either parameter is uninitialized, the resulting LiveData is also uninitialized.
493      * <p>
494      * This is equivalent to calling {@code combine(tData, uData, Pair::new)}.
495      *
496      * @see #combine(LiveData, LiveData, BiFunction)
497      */
498     public static <T, U> LiveData<Pair<T, U>> pair(
499             @NonNull LiveData<T> tData, @NonNull LiveData<U> uData) {
500         return combine(tData, uData, Pair::new);
501     }
502 
503     /**
504      * Returns an observer that splits a pair into two separate arguments. This method is mainly
505      * used to simplify lambda expressions and enable method references, especially in combination
506      * with {@link #pair(LiveData, LiveData)}.
507      * <p>
508      * Example:
509      * <pre><code>
510      * class MyViewModel extends ViewModel {
511      *   LiveData&lt;Integer> getIntData() {...}
512      *   LiveData&lt;Boolean> getBoolData() {...}
513      * }
514      *
515      * void consume(int intValue, boolean booleanValue) {...}
516      *
517      * void startObserving(MyViewModel viewModel) {
518      *   pair(viewModel.getIntData(), viewModel.getBoolData()).observe(owner, split(this::consume));
519      * }</code></pre>
520      */
521     public static <T, U> Observer<Pair<T, U>> split(@NonNull BiConsumer<T, U> consumer) {
522         return (pair) -> {
523             if (pair == null) {
524                 consumer.accept(null, null);
525             } else {
526                 consumer.accept(pair.first, pair.second);
527             }
528         };
529     }
530 
531     /**
532      * Returns a switch Function that splits a pair into two separate arguments. This method is
533      * mainly used to simplify lambda expressions and enable method references for {@link
534      * Transformations#switchMap(LiveData, Function) switchMaps}, especially in combination with
535      * {@link #pair(LiveData, LiveData)}.
536      */
537     public static <T, U, V> Function<Pair<T, U>, LiveData<V>> split(
538             @NonNull BiFunction<T, U, LiveData<V>> function) {
539         return (pair) -> {
540             if (pair == null) {
541                 return function.apply(null, null);
542             } else {
543                 return function.apply(pair.first, pair.second);
544             }
545         };
546     }
547 
548     /**
549      * Returns a LiveData that emits the result of {@code function} on the values of the two
550      * parameter LiveDatas. If either parameter is uninitialized, the resulting LiveData is also
551      * uninitialized.
552      */
553     public static <T, U, R> LiveData<R> combine(
554             @NonNull LiveData<T> tData,
555             @NonNull LiveData<U> uData,
556             @NonNull BiFunction<T, U, R> function) {
557         return new BinaryOperation<>(tData, uData, function);
558     }
559 
560     private static class BinaryOperation<T, U, R> extends MediatorLiveData<R> {
561         @NonNull
562         private final BiFunction<T, U, R> mFunction;
563 
564         private boolean mTSet;
565         private boolean mUSet;
566         private boolean mValueSet;
567 
568         @Nullable
569         private T mTValue;
570         @Nullable
571         private U mUValue;
572 
573         BinaryOperation(
574                 @NonNull LiveData<T> tLiveData,
575                 @NonNull LiveData<U> uLiveData,
576                 @NonNull BiFunction<T, U, R> function) {
577             this(tLiveData, uLiveData, true, true, function);
578         }
579 
580         BinaryOperation(
581                 @NonNull LiveData<T> tLiveData,
582                 @NonNull LiveData<U> uLiveData,
583                 boolean requireTSet,
584                 boolean requireUSet,
585                 @NonNull BiFunction<T, U, R> function) {
586             this.mFunction = function;
587             if (!requireTSet) {
588                 mTSet = true;
589             }
590             if (!requireUSet) {
591                 mUSet = true;
592             }
593             if (tLiveData == uLiveData) {
594                 // Only add the source once and only update once when it changes.
595                 addSource(
596                         tLiveData,
597                         value -> {
598                             mTSet = true;
599                             mUSet = true;
600                             mTValue = value;
601                             // if both references point to the same LiveData, then T and U are
602                             // compatible types.
603                             // noinspection unchecked
604                             mUValue = (U) value;
605                             update();
606                         });
607             } else {
608                 addSource(requireNonNull(tLiveData), this::updateT);
609                 addSource(requireNonNull(uLiveData), this::updateU);
610             }
611         }
612 
613         private void updateT(@Nullable T tValue) {
614             mTSet = true;
615             this.mTValue = tValue;
616             update();
617         }
618 
619         private void updateU(@Nullable U uValue) {
620             mUSet = true;
621             this.mUValue = uValue;
622             update();
623         }
624 
625         private void update() {
626             if (mTSet && mUSet) {
627                 R result = mFunction.apply(mTValue, mUValue);
628                 // Don't setValue if it's the same as the old value unless we haven't set a value
629                 // before.
630                 if (!mValueSet || result != getValue()) {
631                     mValueSet = true;
632                     setValue(result);
633                 }
634             }
635         }
636     }
637 }
638