1 /*
2  * Copyright (C) 2021 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.car.settings.enterprise;
17 
18 import android.annotation.Nullable;
19 import android.car.drivingstate.CarUxRestrictions;
20 import android.content.Context;
21 
22 import androidx.preference.Preference;
23 
24 import com.android.car.settings.common.FragmentController;
25 import com.android.car.settings.enterprise.CallbackTranslator.Callback;
26 import com.android.car.settingslib.applications.ApplicationFeatureProvider;
27 
28 /**
29  * Base class for async controllers.
30  */
31 abstract class BaseAsyncPreferenceController<P extends Preference, R,
32         T extends CallbackTranslator<R>> extends BaseEnterprisePrivacyPreferenceController<P> {
33 
34     private R mResult;
35 
36     @Nullable
37     private T mCallbackTranslator;
38 
39     @Nullable
40     private Integer mAvailabilityStatus;
41 
BaseAsyncPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions, @Nullable ApplicationFeatureProvider applicationFeatureProvider)42     protected BaseAsyncPreferenceController(Context context,
43             String preferenceKey, FragmentController fragmentController,
44             CarUxRestrictions uxRestrictions,
45             @Nullable ApplicationFeatureProvider applicationFeatureProvider) {
46         super(context, preferenceKey, fragmentController, uxRestrictions,
47                 /* enterprisePrivacyFeatureProvider= */ null, applicationFeatureProvider);
48     }
49 
50     /**
51      * Calls the method that will lazy-load the counter.
52      */
lazyLoad(T callbackHolder)53     protected abstract void lazyLoad(T callbackHolder);
54 
55     /**
56      * Creates a translator between this class Callback and {@code SettingsLib}.
57      * @param callback
58      * @return
59      */
newCallbackTranslator(Callback<R> callback)60     protected abstract T newCallbackTranslator(Callback<R> callback);
61 
62     /**
63      * Checks if the result of the callback should make the controller available.
64      */
isAvailable(R result)65     protected abstract boolean isAvailable(R result);
66 
67     /**
68      * Gets the result returned by the callback.
69      */
getResult()70     protected R getResult() {
71         return mResult;
72     }
73 
74     @Override
getDefaultAvailabilityStatus()75     protected final int getDefaultAvailabilityStatus() {
76         if (mAvailabilityStatus != null) {
77             // Already calculated
78             mLogger.d("getAvailabilityStatus(): returning cached result " + mAvailabilityStatus);
79             return mAvailabilityStatus;
80         }
81 
82         if (mCallbackTranslator != null) {
83             mLogger.d("getAvailabilityStatus(): already waiting for callback...");
84         } else {
85             mLogger.d("getAvailabilityStatus(): lazy-loading number of apps");
86             mCallbackTranslator = newCallbackTranslator((result) -> onLazyLoaded(result));
87             lazyLoad(mCallbackTranslator);
88         }
89 
90         // Calculating the number of apps can takes a bit of time, so we always return
91         // CONDITIONALLY_UNAVAILABLE, so the actual visibility will be set when the result is called
92         // back (on onLazyLoaded()).
93         return CONDITIONALLY_UNAVAILABLE;
94     }
95 
onLazyLoaded(R result)96     private void onLazyLoaded(R result) {
97         mResult = result;
98         boolean available = isAvailable(result);
99         mAvailabilityStatus = available
100                 ? AVAILABLE
101                 : DISABLED_FOR_PROFILE;
102         mLogger.d("onLazyLoaded(): result=" + result + ", available=" + available);
103 
104         if (available)  {
105             refreshUi();
106         }
107     }
108 }
109