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