1 /*
2  * Copyright (C) 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 package com.android.launcher3.util;
17 
18 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
19 
20 import android.content.Context;
21 import android.os.Looper;
22 
23 import androidx.annotation.VisibleForTesting;
24 
25 import com.android.launcher3.util.ResourceBasedOverride.Overrides;
26 
27 import java.util.concurrent.ExecutionException;
28 
29 /**
30  * Utility class for defining singletons which are initiated on main thread.
31  */
32 public class MainThreadInitializedObject<T> {
33 
34     private final ObjectProvider<T> mProvider;
35     private T mValue;
36 
MainThreadInitializedObject(ObjectProvider<T> provider)37     public MainThreadInitializedObject(ObjectProvider<T> provider) {
38         mProvider = provider;
39     }
40 
get(Context context)41     public T get(Context context) {
42         if (mValue == null) {
43             if (Looper.myLooper() == Looper.getMainLooper()) {
44                 mValue = mProvider.get(context.getApplicationContext());
45             } else {
46                 try {
47                     return MAIN_EXECUTOR.submit(() -> get(context)).get();
48                 } catch (InterruptedException|ExecutionException e) {
49                     throw new RuntimeException(e);
50                 }
51             }
52         }
53         return mValue;
54     }
55 
getNoCreate()56     public T getNoCreate() {
57         return mValue;
58     }
59 
60     @VisibleForTesting
initializeForTesting(T value)61     public void initializeForTesting(T value) {
62         mValue = value;
63     }
64 
65     /**
66      * Initializes a provider based on resource overrides
67      */
forOverride( Class<T> clazz, int resourceId)68     public static <T extends ResourceBasedOverride> MainThreadInitializedObject<T> forOverride(
69             Class<T> clazz, int resourceId) {
70         return new MainThreadInitializedObject<>(c -> Overrides.getObject(clazz, c, resourceId));
71     }
72 
73     public interface ObjectProvider<T> {
74 
get(Context context)75         T get(Context context);
76     }
77 }
78