blob: b07c4538bc5f47c611b28afc723db6780af3aebc [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.providers.media.photopicker.viewmodel;
import static android.content.Intent.ACTION_GET_CONTENT;
import static android.content.Intent.EXTRA_LOCAL_ONLY;
import static com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_COLLAPSED;
import static com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED;
import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.UserHandle;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import com.android.internal.logging.InstanceId;
import com.android.internal.logging.InstanceIdSequence;
import com.android.modules.utils.build.SdkLevel;
import com.android.providers.media.ConfigStore;
import com.android.providers.media.MediaApplication;
import com.android.providers.media.photopicker.data.ItemsProvider;
import com.android.providers.media.photopicker.data.MuteStatus;
import com.android.providers.media.photopicker.data.Selection;
import com.android.providers.media.photopicker.data.UserIdManager;
import com.android.providers.media.photopicker.data.model.Category;
import com.android.providers.media.photopicker.data.model.Item;
import com.android.providers.media.photopicker.data.model.UserId;
import com.android.providers.media.photopicker.metrics.PhotoPickerUiEventLogger;
import com.android.providers.media.photopicker.util.MimeFilterUtils;
import com.android.providers.media.util.ForegroundThread;
import com.android.providers.media.util.MimeUtils;
import com.android.providers.media.util.PerUser;
import java.util.ArrayList;
import java.util.List;
/**
* PickerViewModel to store and handle data for PhotoPickerActivity.
*/
public class PickerViewModel extends AndroidViewModel {
public static final String TAG = "PhotoPicker";
private static final int RECENT_MINIMUM_COUNT = 12;
private static final int INSTANCE_ID_MAX = 1 << 15;
@NonNull
@SuppressLint("StaticFieldLeak")
private final Context mAppContext;
private final Selection mSelection;
private final MuteStatus mMuteStatus;
// TODO(b/193857982): We keep these four data sets now, we may need to find a way to reduce the
// data set to reduce memories.
// The list of Items with all photos and videos
private MutableLiveData<List<Item>> mItemList;
// The list of Items with all photos and videos in category
private MutableLiveData<List<Item>> mCategoryItemList;
// The list of categories.
private MutableLiveData<List<Category>> mCategoryList;
// Authority of the current CloudMediaProvider of the current user
private final MutableLiveData<String> mCloudMediaProviderAuthority = new MutableLiveData<>();
// Label of the current CloudMediaProvider of the current user
private final MutableLiveData<String> mCloudMediaProviderLabel = new MutableLiveData<>();
// Account name of the current CloudMediaProvider of the current user
private final MutableLiveData<String> mCloudMediaAccountName = new MutableLiveData<>();
// Boolean Choose App Banner visibility
private final MutableLiveData<Boolean> mShowChooseAppBanner = new MutableLiveData<>(false);
// Boolean Cloud Media Available Banner visibility
private final MutableLiveData<Boolean> mShowCloudMediaAvailableBanner =
new MutableLiveData<>(false);
// Boolean 'Account Updated' banner visibility
private final MutableLiveData<Boolean> mShowAccountUpdatedBanner = new MutableLiveData<>(false);
// Boolean 'Choose Account' banner visibility
private final MutableLiveData<Boolean> mShowChooseAccountBanner = new MutableLiveData<>(false);
// The banner controllers per user
private final PerUser<BannerController> mBannerControllers = new PerUser<BannerController>() {
@NonNull
@Override
protected BannerController create(@UserIdInt int userId) {
return new BannerController(mAppContext, UserHandle.of(userId));
}
};
private ItemsProvider mItemsProvider;
private UserIdManager mUserIdManager;
private boolean mIsUserSelectForApp;
private InstanceId mInstanceId;
private PhotoPickerUiEventLogger mLogger;
private String[] mMimeTypeFilters = null;
private int mBottomSheetState;
private Category mCurrentCategory;
private ConfigStore mConfigStore;
private boolean mIsLocalOnly;
public PickerViewModel(@NonNull Application application) {
super(application);
mAppContext = application.getApplicationContext();
mItemsProvider = new ItemsProvider(mAppContext);
mSelection = new Selection();
mUserIdManager = UserIdManager.create(mAppContext);
mMuteStatus = new MuteStatus();
mInstanceId = new InstanceIdSequence(INSTANCE_ID_MAX).newInstanceId();
mLogger = new PhotoPickerUiEventLogger();
mConfigStore = MediaApplication.getConfigStore();
mIsUserSelectForApp = false;
mIsLocalOnly = false;
maybeInitialiseAndSetBannersForCurrentUser();
}
@VisibleForTesting
public void setItemsProvider(@NonNull ItemsProvider itemsProvider) {
mItemsProvider = itemsProvider;
}
@VisibleForTesting
public void setUserIdManager(@NonNull UserIdManager userIdManager) {
mUserIdManager = userIdManager;
}
/**
* @return {@link UserIdManager} for this context.
*/
public UserIdManager getUserIdManager() {
return mUserIdManager;
}
/**
* @return {@code mSelection} that manages the selection
*/
public Selection getSelection() {
return mSelection;
}
/**
* @return {@code mMuteStatus} that tracks the volume mute status of the video preview
*/
public MuteStatus getMuteStatus() {
return mMuteStatus;
}
/**
* @return {@code mIsUserSelectForApp} if the picker is currently being used
* for the {@link MediaStore#ACTION_USER_SELECT_IMAGES_FOR_APP} action.
*/
public boolean isUserSelectForApp() {
return mIsUserSelectForApp;
}
/**
* @return a {@link LiveData} that holds the value (once it's fetched) of the
* {@link android.content.ContentProvider#mAuthority authority} of the current
* {@link android.provider.CloudMediaProvider}.
*/
@NonNull
public LiveData<String> getCloudMediaProviderAuthorityLiveData() {
return mCloudMediaProviderAuthority;
}
/**
* @return a {@link LiveData} that holds the value (once it's fetched) of the label
* of the current {@link android.provider.CloudMediaProvider}.
*/
@NonNull
public LiveData<String> getCloudMediaProviderAppTitleLiveData() {
return mCloudMediaProviderLabel;
}
/**
* @return a {@link LiveData} that holds the value (once it's fetched) of the account name
* of the current {@link android.provider.CloudMediaProvider}.
*/
@NonNull
public LiveData<String> getCloudMediaAccountNameLiveData() {
return mCloudMediaAccountName;
}
/**
* Reset PickerViewModel.
* @param switchToPersonalProfile is true then set personal profile as current profile.
*/
public void reset(boolean switchToPersonalProfile) {
// 1. Clear Selected items
mSelection.clearSelectedItems();
// 2. Change profile to personal user
if (switchToPersonalProfile) {
mUserIdManager.setPersonalAsCurrentUserProfile();
}
// 3. Update Item and Category lists
updateItems();
updateCategories();
// 4. Update Banners
// Note - Banners should always be updated after the items & categories to ensure a
// consistent UI.
updateBanners();
}
/**
* @return the list of Items with all photos and videos {@link #mItemList} on the device.
*/
public LiveData<List<Item>> getItems() {
if (mItemList == null) {
updateItems();
}
return mItemList;
}
private List<Item> loadItems(Category category, UserId userId) {
final List<Item> items = new ArrayList<>();
try (Cursor cursor = fetchItems(category, userId)) {
if (cursor == null || cursor.getCount() == 0) {
Log.d(TAG, "Didn't receive any items for " + category
+ ", either cursor is null or cursor count is zero");
return items;
}
while (cursor.moveToNext()) {
// TODO(b/188394433): Return userId in the cursor so that we do not need to pass it
// here again.
items.add(Item.fromCursor(cursor, userId));
}
}
Log.d(TAG, "Loaded " + items.size() + " items in " + category + " for user "
+ userId.toString());
return items;
}
private Cursor fetchItems(Category category, UserId userId) {
if (isUserSelectForApp() || isLocalOnly()) {
// We only show local items in below cases.
// 1. Photo Picker is launched by {@link MediaStore#ACTION_USER_SELECT_IMAGES_FOR_APP}
// action for permission flow.
// 2. Photo Picker is launched with {@link EXTRA_LOCAL_ONLY} as true in
// {@link ACTION_GET_CONTENT} or {@link ACTION_PICK_IMAGES}.
return mItemsProvider.getLocalItems(category, /* limit */ -1, mMimeTypeFilters, userId);
} else {
return mItemsProvider.getAllItems(category, /* limit */ -1, mMimeTypeFilters, userId);
}
}
private void loadItemsAsync() {
final UserId userId = mUserIdManager.getCurrentUserProfileId();
ForegroundThread.getExecutor().execute(() -> {
mItemList.postValue(loadItems(Category.DEFAULT, userId));
});
}
/**
* Update the item List {@link #mItemList}
*/
public void updateItems() {
if (mItemList == null) {
mItemList = new MutableLiveData<>();
}
loadItemsAsync();
}
/**
* Get the list of all photos and videos with the specific {@code category} on the device.
*
* In our use case, we only keep the list of current category {@link #mCurrentCategory} in
* {@link #mCategoryItemList}. If the {@code category} and {@link #mCurrentCategory} are
* different, we will create the new LiveData to {@link #mCategoryItemList}.
*
* @param category the category we want to be queried
* @return the list of all photos and videos with the specific {@code category}
* {@link #mCategoryItemList}
*/
public LiveData<List<Item>> getCategoryItems(@NonNull Category category) {
if (mCategoryItemList == null || !TextUtils.equals(mCurrentCategory.getId(),
category.getId())) {
mCategoryItemList = new MutableLiveData<>();
mCurrentCategory = category;
}
updateCategoryItems();
return mCategoryItemList;
}
private void loadCategoryItemsAsync() {
final UserId userId = mUserIdManager.getCurrentUserProfileId();
ForegroundThread.getExecutor().execute(() -> {
mCategoryItemList.postValue(loadItems(mCurrentCategory, userId));
});
}
/**
* Update the item List with the {@link #mCurrentCategory} {@link #mCategoryItemList}
*
* @throws IllegalStateException category and category items is not initiated before calling
* this method
*/
@VisibleForTesting
public void updateCategoryItems() {
if (mCategoryItemList == null || mCurrentCategory == null) {
throw new IllegalStateException("mCurrentCategory and mCategoryItemList are not"
+ " initiated. Please call getCategoryItems before calling this method");
}
loadCategoryItemsAsync();
}
/**
* @return the list of Categories {@link #mCategoryList}
*/
public LiveData<List<Category>> getCategories() {
if (mCategoryList == null) {
updateCategories();
}
return mCategoryList;
}
private List<Category> loadCategories(UserId userId) {
final List<Category> categoryList = new ArrayList<>();
try (Cursor cursor = fetchCategories(userId)) {
if (cursor == null || cursor.getCount() == 0) {
Log.d(TAG, "Didn't receive any categories, either cursor is null or"
+ " cursor count is zero");
return categoryList;
}
while (cursor.moveToNext()) {
final Category category = Category.fromCursor(cursor, userId);
categoryList.add(category);
}
Log.d(TAG,
"Loaded " + categoryList.size() + " categories for user " + userId.toString());
}
return categoryList;
}
private Cursor fetchCategories(UserId userId) {
if (isUserSelectForApp() || isLocalOnly()) {
// We only show local items in below cases.
// 1. Photo Picker is launched by {@link MediaStore#ACTION_USER_SELECT_IMAGES_FOR_APP}
// action for permission flow.
// 2. Photo Picker is launched with {@link EXTRA_LOCAL_ONLY} as true in
// {@link ACTION_GET_CONTENT} or {@link ACTION_PICK_IMAGES}.
return mItemsProvider.getLocalCategories(mMimeTypeFilters, userId);
} else {
return mItemsProvider.getAllCategories(mMimeTypeFilters, userId);
}
}
private void loadCategoriesAsync() {
final UserId userId = mUserIdManager.getCurrentUserProfileId();
ForegroundThread.getExecutor().execute(() -> {
mCategoryList.postValue(loadCategories(userId));
});
}
/**
* Update the category List {@link #mCategoryList}
*/
public void updateCategories() {
if (mCategoryList == null) {
mCategoryList = new MutableLiveData<>();
}
loadCategoriesAsync();
}
/**
* Return whether the {@link #mMimeTypeFilters} is {@code null} or not
*/
public boolean hasMimeTypeFilters() {
return mMimeTypeFilters != null && mMimeTypeFilters.length > 0;
}
private boolean isAllImagesFilter() {
return mMimeTypeFilters != null && mMimeTypeFilters.length == 1
&& MimeUtils.isAllImagesMimeType(mMimeTypeFilters[0]);
}
private boolean isAllVideosFilter() {
return mMimeTypeFilters != null && mMimeTypeFilters.length == 1
&& MimeUtils.isAllVideosMimeType(mMimeTypeFilters[0]);
}
/**
* Parse values from {@code intent} and set corresponding fields
*/
public void parseValuesFromIntent(Intent intent) throws IllegalArgumentException {
mUserIdManager.setIntentAndCheckRestrictions(intent);
mMimeTypeFilters = MimeFilterUtils.getMimeTypeFilters(intent);
mSelection.parseSelectionValuesFromIntent(intent);
mIsLocalOnly = intent.getBooleanExtra(EXTRA_LOCAL_ONLY, false);
mIsUserSelectForApp =
MediaStore.ACTION_USER_SELECT_IMAGES_FOR_APP.equals(intent.getAction());
if (!SdkLevel.isAtLeastU() && mIsUserSelectForApp) {
throw new IllegalArgumentException("ACTION_USER_SELECT_IMAGES_FOR_APP is not enabled "
+ " for this OS version");
}
// Ensure that if Photopicker is being used for permissions the target app UID is present
// in the extras.
if (mIsUserSelectForApp
&& (intent.getExtras() == null
|| !intent.getExtras()
.containsKey(Intent.EXTRA_UID))) {
throw new IllegalArgumentException(
"EXTRA_UID is required for" + " ACTION_USER_SELECT_IMAGES_FOR_APP");
}
}
/**
* Set BottomSheet state
*/
public void setBottomSheetState(int state) {
mBottomSheetState = state;
}
/**
* @return BottomSheet state
*/
public int getBottomSheetState() {
return mBottomSheetState;
}
/**
* Log picker opened metrics
*/
public void logPickerOpened(int callingUid, String callingPackage, String intentAction) {
if (getUserIdManager().isManagedUserSelected()) {
mLogger.logPickerOpenWork(mInstanceId, callingUid, callingPackage);
} else {
mLogger.logPickerOpenPersonal(mInstanceId, callingUid, callingPackage);
}
// TODO(b/235326735): Optimise logging multiple times on picker opened
// TODO(b/235326736): Check if we should add a metric for PICK_IMAGES intent to simplify
// metrics reading
if (ACTION_GET_CONTENT.equals(intentAction)) {
mLogger.logPickerOpenViaGetContent(mInstanceId, callingUid, callingPackage);
}
if (mBottomSheetState == STATE_COLLAPSED) {
mLogger.logPickerOpenInHalfScreen(mInstanceId, callingUid, callingPackage);
} else if (mBottomSheetState == STATE_EXPANDED) {
mLogger.logPickerOpenInFullScreen(mInstanceId, callingUid, callingPackage);
}
if (mSelection != null && mSelection.canSelectMultiple()) {
mLogger.logPickerOpenInMultiSelect(mInstanceId, callingUid, callingPackage);
} else {
mLogger.logPickerOpenInSingleSelect(mInstanceId, callingUid, callingPackage);
}
if (isAllImagesFilter()) {
mLogger.logPickerOpenWithFilterAllImages(mInstanceId, callingUid, callingPackage);
} else if (isAllVideosFilter()) {
mLogger.logPickerOpenWithFilterAllVideos(mInstanceId, callingUid, callingPackage);
} else if (hasMimeTypeFilters()) {
mLogger.logPickerOpenWithAnyOtherFilter(mInstanceId, callingUid, callingPackage);
}
maybeLogPickerOpenedWithCloudProvider();
}
// TODO(b/245745412): Fix log params (uid & package name)
// TODO(b/245745424): Solve for active cloud provider without a logged in account
private void maybeLogPickerOpenedWithCloudProvider() {
mCloudMediaProviderAuthority.observeForever(new Observer<String>() {
@Override
public void onChanged(@Nullable String providerAuthority) {
Log.d(TAG, "logPickerOpenedWithCloudProvider() provider=" + providerAuthority
+ ", log=" + (providerAuthority != null));
if (providerAuthority != null) {
mLogger.logPickerOpenWithActiveCloudProvider(
mInstanceId, /* cloudProviderUid */ -1, providerAuthority);
}
// We only need to get the value once.
mCloudMediaProviderAuthority.removeObserver(this);
}
});
}
/**
* Log metrics to notify that the user has clicked Browse to open DocumentsUi
*/
public void logBrowseToDocumentsUi(int callingUid, String callingPackage) {
mLogger.logBrowseToDocumentsUi(mInstanceId, callingUid, callingPackage);
}
/**
* Log metrics to notify that the user has confirmed selection
*/
public void logPickerConfirm(int callingUid, String callingPackage, int countOfItemsConfirmed) {
if (getUserIdManager().isManagedUserSelected()) {
mLogger.logPickerConfirmWork(mInstanceId, callingUid, callingPackage,
countOfItemsConfirmed);
} else {
mLogger.logPickerConfirmPersonal(mInstanceId, callingUid, callingPackage,
countOfItemsConfirmed);
}
}
/**
* Log metrics to notify that the user has exited Picker without any selection
*/
public void logPickerCancel(int callingUid, String callingPackage) {
if (getUserIdManager().isManagedUserSelected()) {
mLogger.logPickerCancelWork(mInstanceId, callingUid, callingPackage);
} else {
mLogger.logPickerCancelPersonal(mInstanceId, callingUid, callingPackage);
}
}
public InstanceId getInstanceId() {
return mInstanceId;
}
public void setInstanceId(InstanceId parcelable) {
mInstanceId = parcelable;
}
public ConfigStore getConfigStore() {
return mConfigStore;
}
/**
* Note - This method is expected to be called only on
* {@link android.provider.CloudMediaProvider} app / account change, i.e. currently on
* {@link #reset(boolean)}
*/
private void updateBanners() {
if (mUserIdManager.isMultiUserProfiles()) {
updateBannersForUser(mUserIdManager.getPersonalUserId());
updateBannersForUser(mUserIdManager.getManagedUserId());
} else {
updateBannersForUser(mUserIdManager.getCurrentUserProfileId());
}
maybeInitialiseAndSetBannersForCurrentUser();
}
// Return whether hotopicker's launch intent has extra {@link EXTRA_LOCAL_ONLY} set to true
// or not.
public boolean isLocalOnly() {
return mIsLocalOnly;
}
/**
* Note - This method is expected to be called only on
* {@link android.provider.CloudMediaProvider} app / account change, i.e. currently on
* {@link #reset(boolean)}
*/
private void updateBannersForUser(@NonNull UserId userId) {
final int userIdInt = userId.getIdentifier();
final BannerController bannerController = mBannerControllers.get(userIdInt);
/**
* {@link BannerController} can be {@code null} for the given {@link UserId} when
* {@link #reset(boolean)} is called before {@link BannerController} construction for this
* {@link UserId}. This is expected to occur for the {@link UserId} that the picker was not
* launched from when
* {@link UserIdManager#isMultiUserProfiles()} is {@code true}, but the user never switched
* profiles before a {@link #reset(boolean)}. In this case, we can skip the
* {@link BannerController} construction until the user actually switches profiles.
*/
if (bannerController != null) {
/**
* {@link BannerController#reset()} cannot be called in the UI thread hence,
* using {@link ForegroundThread} here.
*/
ForegroundThread.getExecutor().execute(bannerController::reset);
}
}
/**
* Set the banner {@link LiveData} values as per the current user {@link BannerController} data.
*
* 1. {@link #hideAllBanners()} in the Main thread to ensure consistency with the media items
* displayed for the period when the items and categories have been updated but the
* {@link BannerController} construction or {@link BannerController#reset()} is still in
* progress.
*
* 2. Get or create the {@link BannerController} for
* {@link UserIdManager#getCurrentUserProfileId()} using {@link PerUser#forUser(int)}.
* Since, the BannerController construction cannot be done in the Main thread, using
* {@link ForegroundThread} here.
*
* 3. Post the updated {@link BannerController} {@link LiveData} values.
*
* Note - This method is expected to be called only in the following scenarios:
* a. {@link PickerViewModel} construction
* b. {@link com.android.providers.media.photopicker.ui.TabFragment#changeProfile}
* c. {@link android.provider.CloudMediaProvider} app / account change, i.e. currently on
* {@link #reset(boolean)}
*/
@UiThread
public void maybeInitialiseAndSetBannersForCurrentUser() {
hideAllBanners();
final int currentUserId = mUserIdManager.getCurrentUserProfileId().getIdentifier();
ForegroundThread.getExecutor().execute(() -> {
final BannerController bannerController = mBannerControllers.forUser(currentUserId);
mCloudMediaProviderAuthority.postValue(
bannerController.getCloudMediaProviderAuthority());
mCloudMediaProviderLabel.postValue(bannerController.getCloudMediaProviderLabel());
mCloudMediaAccountName.postValue(bannerController.getCloudMediaProviderAccountName());
mShowChooseAppBanner.postValue(bannerController.shouldShowChooseAppBanner());
mShowCloudMediaAvailableBanner.postValue(
bannerController.shouldShowCloudMediaAvailableBanner());
mShowAccountUpdatedBanner.postValue(bannerController.shouldShowAccountUpdatedBanner());
mShowChooseAccountBanner.postValue(bannerController.shouldShowChooseAccountBanner());
});
}
/**
* Hide all banners in the Main thread.
*
* Set all banner {@link LiveData} values to {@code false}.
*/
@UiThread
private void hideAllBanners() {
mShowChooseAppBanner.setValue(false);
mShowCloudMediaAvailableBanner.setValue(false);
mShowAccountUpdatedBanner.setValue(false);
mShowChooseAccountBanner.setValue(false);
}
/**
* @return the {@link LiveData} of the 'Choose App' banner visibility
* {@link #mShowChooseAppBanner}.
*/
@NonNull
public LiveData<Boolean> shouldShowChooseAppBannerLiveData() {
return mShowChooseAppBanner;
}
/**
* @return the {@link LiveData} of the 'Cloud Media Available' banner visibility
* {@link #mShowCloudMediaAvailableBanner}.
*/
@NonNull
public LiveData<Boolean> shouldShowCloudMediaAvailableBannerLiveData() {
return mShowCloudMediaAvailableBanner;
}
/**
* @return the {@link LiveData} of the 'Account Updated' banner visibility
* {@link #mShowAccountUpdatedBanner}.
*/
@NonNull
public LiveData<Boolean> shouldShowAccountUpdatedBannerLiveData() {
return mShowAccountUpdatedBanner;
}
/**
* @return the {@link LiveData} of the 'Choose Account' banner visibility
* {@link #mShowChooseAccountBanner}.
*/
@NonNull
public LiveData<Boolean> shouldShowChooseAccountBannerLiveData() {
return mShowChooseAccountBanner;
}
/**
* Dismiss (hide) the 'Choose App' banner for the current user.
*
* 1. Set the {@link LiveData} value of the 'Choose App' banner visibility
* {@link #mShowChooseAppBanner} as {@code false}.
*
* 2. Update the 'Choose App' banner visibility of the current user {@link BannerController} to
* {@code false}.
*/
@UiThread
public void onUserDismissedChooseAppBanner() {
final BannerController bannerController = getCurrentBannerController();
if (bannerController == null) {
Log.wtf(TAG, "Banner controller not yet created for the current user on Choose App"
+ " banner dismiss");
return;
}
if (Boolean.FALSE.equals(mShowChooseAppBanner.getValue())) {
Log.wtf(TAG, "Choose App banner visibility live data value is false on dismiss");
} else {
mShowChooseAppBanner.setValue(false);
}
bannerController.onUserDismissedChooseAppBanner();
}
/**
* Dismiss (hide) the 'Cloud Media Available' banner for the current user.
*
* 1. Set the {@link LiveData} value of the 'Cloud Media Available' banner visibility
* {@link #mShowCloudMediaAvailableBanner} as {@code false}.
*
* 2. Update the 'Cloud Media Available' banner visibility of the current user
* {@link BannerController} to {@code false}.
*/
@UiThread
public void onUserDismissedCloudMediaAvailableBanner() {
final BannerController bannerController = getCurrentBannerController();
if (bannerController == null) {
Log.wtf(TAG, "Banner controller not yet created for the current user on Cloud Media "
+ "Available banner dismiss");
return;
}
if (Boolean.FALSE.equals(mShowCloudMediaAvailableBanner.getValue())) {
Log.wtf(TAG, "Cloud Media Available banner visibility live data value is false on "
+ "dismiss");
} else {
mShowCloudMediaAvailableBanner.setValue(false);
}
bannerController.onUserDismissedCloudMediaAvailableBanner();
}
/**
* Dismiss (hide) the 'Account Updated' banner for the current user.
*
* 1. Set the {@link LiveData} value of the 'Account Updated' banner visibility
* {@link #mShowAccountUpdatedBanner} as {@code false}.
*
* 2. Update the 'Account Updated' banner visibility of the current user
* {@link BannerController} to {@code false}.
*/
@UiThread
public void onUserDismissedAccountUpdatedBanner() {
final BannerController bannerController = getCurrentBannerController();
if (bannerController == null) {
Log.wtf(TAG, "Banner controller not yet created for the current user on Account Updated"
+ " banner dismiss");
return;
}
if (Boolean.FALSE.equals(mShowAccountUpdatedBanner.getValue())) {
Log.wtf(TAG, "Account Updated banner visibility live data value is false on dismiss");
} else {
mShowAccountUpdatedBanner.setValue(false);
}
bannerController.onUserDismissedAccountUpdatedBanner();
}
/**
* Dismiss (hide) the 'Choose Account' banner for the current user.
*
* 1. Set the {@link LiveData} value of the 'Choose Account' banner visibility
* {@link #mShowChooseAccountBanner} as {@code false}.
*
* 2. Update the 'Choose Account' banner visibility of the current user
* {@link BannerController} to {@code false}.
*/
@UiThread
public void onUserDismissedChooseAccountBanner() {
final BannerController bannerController = getCurrentBannerController();
if (bannerController == null) {
Log.wtf(TAG, "Banner controller not yet created for the current user on Choose Account"
+ " banner dismiss");
return;
}
if (Boolean.FALSE.equals(mShowChooseAccountBanner.getValue())) {
Log.wtf(TAG, "Choose Account banner visibility live data value is false on dismiss");
} else {
mShowChooseAccountBanner.setValue(false);
}
bannerController.onUserDismissedChooseAccountBanner();
}
@Nullable
private BannerController getCurrentBannerController() {
final int currentUserId = mUserIdManager.getCurrentUserProfileId().getIdentifier();
return mBannerControllers.get(currentUserId);
}
}