• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.providers.media.photopicker.viewmodel;
18 
19 import android.annotation.UserIdInt;
20 import android.content.Context;
21 import android.os.UserHandle;
22 import android.util.Log;
23 
24 import androidx.annotation.NonNull;
25 import androidx.annotation.Nullable;
26 import androidx.annotation.UiThread;
27 import androidx.lifecycle.LiveData;
28 import androidx.lifecycle.MutableLiveData;
29 
30 import com.android.providers.media.photopicker.data.UserIdManager;
31 import com.android.providers.media.util.ForegroundThread;
32 import com.android.providers.media.util.PerUser;
33 
34 class BannerManager {
35     private static final String TAG = "BannerManager";
36 
37     private final UserIdManager mUserIdManager;
38 
39     // Authority of the current CloudMediaProvider of the current user
40     private final MutableLiveData<String> mCloudMediaProviderAuthority = new MutableLiveData<>();
41     // Label of the current CloudMediaProvider of the current user
42     private final MutableLiveData<String> mCloudMediaProviderLabel = new MutableLiveData<>();
43     // Account name of the current CloudMediaProvider of the current user
44     private final MutableLiveData<String> mCloudMediaAccountName = new MutableLiveData<>();
45 
46     // Boolean Choose App Banner visibility
47     private final MutableLiveData<Boolean> mShowChooseAppBanner = new MutableLiveData<>(false);
48     // Boolean Cloud Media Available Banner visibility
49     private final MutableLiveData<Boolean> mShowCloudMediaAvailableBanner =
50             new MutableLiveData<>(false);
51     // Boolean 'Account Updated' banner visibility
52     private final MutableLiveData<Boolean> mShowAccountUpdatedBanner = new MutableLiveData<>(false);
53     // Boolean 'Choose Account' banner visibility
54     private final MutableLiveData<Boolean> mShowChooseAccountBanner = new MutableLiveData<>(false);
55 
56     // The banner controllers per user
57     private final PerUser<BannerController> mBannerControllers;
58 
BannerManager(@onNull Context context, @NonNull UserIdManager userIdManager)59     BannerManager(@NonNull Context context, @NonNull UserIdManager userIdManager) {
60         mUserIdManager = userIdManager;
61         mBannerControllers = new PerUser<BannerController>() {
62             @NonNull
63             @Override
64             protected BannerController create(@UserIdInt int userId) {
65                 return new BannerController(context, UserHandle.of(userId));
66             }
67         };
68         maybeInitialiseAndSetBannersForCurrentUser();
69     }
70 
getCurrentUserProfileId()71     @UserIdInt int getCurrentUserProfileId() {
72         return mUserIdManager.getCurrentUserProfileId().getIdentifier();
73     }
74 
getBannerControllersPerUser()75     PerUser<BannerController> getBannerControllersPerUser() {
76         return mBannerControllers;
77     }
78 
79     /**
80      * @return a {@link LiveData} that holds the value (once it's fetched) of the
81      *         {@link android.content.ContentProvider#mAuthority authority} of the current
82      *         {@link android.provider.CloudMediaProvider}.
83      */
84     @NonNull
getCloudMediaProviderAuthorityLiveData()85     MutableLiveData<String> getCloudMediaProviderAuthorityLiveData() {
86         return mCloudMediaProviderAuthority;
87     }
88 
89     /**
90      * @return a {@link LiveData} that holds the value (once it's fetched) of the label
91      *         of the current {@link android.provider.CloudMediaProvider}.
92      */
93     @NonNull
getCloudMediaProviderAppTitleLiveData()94     MutableLiveData<String> getCloudMediaProviderAppTitleLiveData() {
95         return mCloudMediaProviderLabel;
96     }
97 
98     /**
99      * @return a {@link LiveData} that holds the value (once it's fetched) of the account name
100      *         of the current {@link android.provider.CloudMediaProvider}.
101      */
102     @NonNull
getCloudMediaAccountNameLiveData()103     MutableLiveData<String> getCloudMediaAccountNameLiveData() {
104         return mCloudMediaAccountName;
105     }
106 
107     /**
108      * @return the {@link LiveData} of the 'Choose App' banner visibility.
109      */
110     @NonNull
shouldShowChooseAppBannerLiveData()111     MutableLiveData<Boolean> shouldShowChooseAppBannerLiveData() {
112         return mShowChooseAppBanner;
113     }
114 
115     /**
116      * @return the {@link LiveData} of the 'Cloud Media Available' banner visibility.
117      */
118     @NonNull
shouldShowCloudMediaAvailableBannerLiveData()119     MutableLiveData<Boolean> shouldShowCloudMediaAvailableBannerLiveData() {
120         return mShowCloudMediaAvailableBanner;
121     }
122 
123     /**
124      * @return the {@link LiveData} of the 'Account Updated' banner visibility.
125      */
126     @NonNull
shouldShowAccountUpdatedBannerLiveData()127     MutableLiveData<Boolean> shouldShowAccountUpdatedBannerLiveData() {
128         return mShowAccountUpdatedBanner;
129     }
130 
131     /**
132      * @return the {@link LiveData} of the 'Choose Account' banner visibility.
133      */
134     @NonNull
shouldShowChooseAccountBannerLiveData()135     MutableLiveData<Boolean> shouldShowChooseAccountBannerLiveData() {
136         return mShowChooseAccountBanner;
137     }
138 
139     /**
140      * Dismiss (hide) the 'Choose App' banner for the current user.
141      */
142     @UiThread
onUserDismissedChooseAppBanner()143     void onUserDismissedChooseAppBanner() {
144         if (Boolean.FALSE.equals(mShowChooseAppBanner.getValue())) {
145             Log.d(TAG, "Choose App banner visibility live data value is false on dismiss");
146         } else {
147             mShowChooseAppBanner.setValue(false);
148         }
149 
150         final BannerController bannerController = getCurrentBannerController();
151         if (bannerController != null) {
152             bannerController.onUserDismissedChooseAppBanner();
153         }
154     }
155 
156     /**
157      * Dismiss (hide) the 'Cloud Media Available' banner for the current user.
158      */
159     @UiThread
onUserDismissedCloudMediaAvailableBanner()160     void onUserDismissedCloudMediaAvailableBanner() {
161         if (Boolean.FALSE.equals(mShowCloudMediaAvailableBanner.getValue())) {
162             Log.d(TAG, "Cloud Media Available banner visibility live data value is false on "
163                     + "dismiss");
164         } else {
165             mShowCloudMediaAvailableBanner.setValue(false);
166         }
167 
168         final BannerController bannerController = getCurrentBannerController();
169         if (bannerController != null) {
170             bannerController.onUserDismissedCloudMediaAvailableBanner();
171         }
172     }
173 
174     /**
175      * Dismiss (hide) the 'Account Updated' banner for the current user.
176      */
177     @UiThread
onUserDismissedAccountUpdatedBanner()178     void onUserDismissedAccountUpdatedBanner() {
179         if (Boolean.FALSE.equals(mShowAccountUpdatedBanner.getValue())) {
180             Log.d(TAG, "Account Updated banner visibility live data value is false on dismiss");
181         } else {
182             mShowAccountUpdatedBanner.setValue(false);
183         }
184 
185         final BannerController bannerController = getCurrentBannerController();
186         if (bannerController != null) {
187             bannerController.onUserDismissedAccountUpdatedBanner();
188         }
189     }
190 
191     /**
192      * Dismiss (hide) the 'Choose Account' banner for the current user.
193      */
194     @UiThread
onUserDismissedChooseAccountBanner()195     void onUserDismissedChooseAccountBanner() {
196         if (Boolean.FALSE.equals(mShowChooseAccountBanner.getValue())) {
197             Log.d(TAG, "Choose Account banner visibility live data value is false on dismiss");
198         } else {
199             mShowChooseAccountBanner.setValue(false);
200         }
201 
202         final BannerController bannerController = getCurrentBannerController();
203         if (bannerController != null) {
204             bannerController.onUserDismissedChooseAccountBanner();
205         }
206     }
207 
208     @Nullable
getCurrentBannerController()209     private BannerController getCurrentBannerController() {
210         final int currentUserProfileId = getCurrentUserProfileId();
211         return mBannerControllers.get(currentUserProfileId);
212     }
213 
214     /**
215      * Resets the banner controller per user.
216      *
217      * Note - Since {@link BannerController#reset()} cannot be called in the Main thread, using
218      * {@link ForegroundThread} here.
219      */
maybeResetAllBannerData()220     void maybeResetAllBannerData() {
221         for (int arrayIndex = 0, numControllers = mBannerControllers.size();
222                 arrayIndex < numControllers; arrayIndex++) {
223             final BannerController bannerController = mBannerControllers.valueAt(arrayIndex);
224             ForegroundThread.getExecutor().execute(bannerController::reset);
225         }
226     }
227 
228     /**
229      * Update the banner {@link LiveData} values.
230      *
231      * 1. {@link #hideAllBanners()} in the Main thread to ensure consistency with the media items
232      * displayed for the period when the items and categories have been updated but the
233      * {@link BannerController} construction or {@link BannerController#reset()} is still in
234      * progress.
235      *
236      * 2. Initialise and set the banner data for the current user
237      * {@link #maybeInitialiseAndSetBannersForCurrentUser()}.
238      */
239     @UiThread
maybeUpdateBannerLiveDatas()240     void maybeUpdateBannerLiveDatas() {
241         // Hide all banners in the Main thread to ensure consistency with the media items
242         hideAllBanners();
243 
244         // Initialise and set the banner data for the current user
245         maybeInitialiseAndSetBannersForCurrentUser();
246     }
247 
248     /**
249      * Hide all banners in the Main thread.
250      *
251      * Set all banner {@link LiveData} values to {@code false}.
252      */
253     @UiThread
hideAllBanners()254     private void hideAllBanners() {
255         mShowChooseAppBanner.setValue(false);
256         mShowCloudMediaAvailableBanner.setValue(false);
257         mShowAccountUpdatedBanner.setValue(false);
258         mShowChooseAccountBanner.setValue(false);
259     }
260 
261 
262     /**
263      * Initialise and set the banner data for the current user.
264      *
265      * No-op by default, overridden for cloud.
266      */
maybeInitialiseAndSetBannersForCurrentUser()267     void maybeInitialiseAndSetBannersForCurrentUser() {
268         // No-op, may be overridden
269     }
270 
271     static class CloudBannerManager extends BannerManager {
CloudBannerManager(@onNull Context context, @NonNull UserIdManager userIdManager)272         CloudBannerManager(@NonNull Context context, @NonNull UserIdManager userIdManager) {
273             super(context, userIdManager);
274         }
275 
276         /**
277          * Initialise and set the banner data for the current user.
278          *
279          * 1. Get or create the {@link BannerController} for
280          * {@link UserIdManager#getCurrentUserProfileId()} using {@link PerUser#forUser(int)}.
281          * Since, the {@link BannerController} construction cannot be done in the Main thread,
282          * using {@link ForegroundThread} here.
283          *
284          * 2. Post the updated {@link BannerController} {@link LiveData} values.
285          */
286         @Override
maybeInitialiseAndSetBannersForCurrentUser()287         void maybeInitialiseAndSetBannersForCurrentUser() {
288             final int currentUserProfileId = getCurrentUserProfileId();
289             ForegroundThread.getExecutor().execute(() -> {
290                 // Get (iff exists) or create the banner controller for the current user
291                 final BannerController bannerController =
292                         getBannerControllersPerUser().forUser(currentUserProfileId);
293                 // Post the banner related live data values from this current user banner controller
294                 getCloudMediaProviderAuthorityLiveData()
295                         .postValue(bannerController.getCloudMediaProviderAuthority());
296                 getCloudMediaProviderAppTitleLiveData()
297                         .postValue(bannerController.getCloudMediaProviderLabel());
298                 getCloudMediaAccountNameLiveData()
299                         .postValue(bannerController.getCloudMediaProviderAccountName());
300                 shouldShowChooseAppBannerLiveData()
301                         .postValue(bannerController.shouldShowChooseAppBanner());
302                 shouldShowCloudMediaAvailableBannerLiveData()
303                         .postValue(bannerController.shouldShowCloudMediaAvailableBanner());
304                 shouldShowAccountUpdatedBannerLiveData()
305                         .postValue(bannerController.shouldShowAccountUpdatedBanner());
306                 shouldShowChooseAccountBannerLiveData()
307                         .postValue(bannerController.shouldShowChooseAccountBanner());
308             });
309         }
310     }
311 }
312