Show other users in storage settings

Bug: 232969364
Test: croot && make RunSettingsRoboTests -j40 ROBOTEST_FILTER="com.android.settings.deviceinfo.storage.NonCurrentUserControllerTest"
Change-Id: I8d933bec8f12faa971684939b722cfae957f4953
This commit is contained in:
Tetiana Meronyk
2022-09-30 10:26:26 +00:00
parent c5bd4228c3
commit 5c0bb75de8
6 changed files with 187 additions and 191 deletions

View File

@@ -73,7 +73,7 @@
android:order="108"/> android:order="108"/>
<!-- Preference order 100~200 are 'ONLY' for storage category preferences above. --> <!-- Preference order 100~200 are 'ONLY' for storage category preferences above. -->
<PreferenceCategory <PreferenceCategory
android:key="pref_secondary_users" android:key="pref_non_current_users"
android:title="@string/storage_other_users" android:title="@string/storage_other_users"
android:order="201" /> android:order="201" />
</PreferenceScreen> </PreferenceScreen>

View File

@@ -92,7 +92,7 @@
android:order="108"/> android:order="108"/>
<!-- Preference order 100~200 are 'ONLY' for storage category preferences above. --> <!-- Preference order 100~200 are 'ONLY' for storage category preferences above. -->
<PreferenceCategory <PreferenceCategory
android:key="pref_secondary_users" android:key="pref_non_current_users"
android:title="@string/storage_other_users" android:title="@string/storage_other_users"
android:order="201" /> android:order="201" />
</PreferenceScreen> </PreferenceScreen>

View File

@@ -16,6 +16,8 @@
package com.android.settings.deviceinfo; package com.android.settings.deviceinfo;
import static java.util.Collections.EMPTY_LIST;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.app.usage.StorageStatsManager; import android.app.usage.StorageStatsManager;
import android.content.Context; import android.content.Context;
@@ -29,13 +31,15 @@ import android.view.View;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.loader.app.LoaderManager; import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader; import androidx.loader.content.Loader;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment; import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
import com.android.settings.deviceinfo.storage.ManageStoragePreferenceController; import com.android.settings.deviceinfo.storage.ManageStoragePreferenceController;
import com.android.settings.deviceinfo.storage.SecondaryUserController; import com.android.settings.deviceinfo.storage.NonCurrentUserController;
import com.android.settings.deviceinfo.storage.StorageAsyncLoader; import com.android.settings.deviceinfo.storage.StorageAsyncLoader;
import com.android.settings.deviceinfo.storage.StorageCacheHelper; import com.android.settings.deviceinfo.storage.StorageCacheHelper;
import com.android.settings.deviceinfo.storage.StorageEntry; import com.android.settings.deviceinfo.storage.StorageEntry;
@@ -49,7 +53,6 @@ import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
/** /**
* Storage Settings main UI is composed by 3 fragments: * Storage Settings main UI is composed by 3 fragments:
@@ -70,6 +73,7 @@ public class StorageCategoryFragment extends DashboardFragment
private static final String TAG = "StorageCategoryFrag"; private static final String TAG = "StorageCategoryFrag";
private static final String SELECTED_STORAGE_ENTRY_KEY = "selected_storage_entry_key"; private static final String SELECTED_STORAGE_ENTRY_KEY = "selected_storage_entry_key";
private static final String SUMMARY_PREF_KEY = "storage_summary"; private static final String SUMMARY_PREF_KEY = "storage_summary";
private static final String TARGET_PREFERENCE_GROUP_KEY = "pref_non_current_users";
private static final int STORAGE_JOB_ID = 0; private static final int STORAGE_JOB_ID = 0;
private static final int ICON_JOB_ID = 1; private static final int ICON_JOB_ID = 1;
private static final int VOLUME_SIZE_JOB_ID = 2; private static final int VOLUME_SIZE_JOB_ID = 2;
@@ -81,7 +85,7 @@ public class StorageCategoryFragment extends DashboardFragment
private SparseArray<StorageAsyncLoader.StorageResult> mAppsResult; private SparseArray<StorageAsyncLoader.StorageResult> mAppsResult;
private StorageItemPreferenceController mPreferenceController; private StorageItemPreferenceController mPreferenceController;
private List<AbstractPreferenceController> mSecondaryUsers; private List<NonCurrentUserController> mNonCurrentUsers;
private boolean mIsWorkProfile; private boolean mIsWorkProfile;
private int mUserId; private int mUserId;
private boolean mIsLoadedFromCache; private boolean mIsLoadedFromCache;
@@ -98,9 +102,9 @@ public class StorageCategoryFragment extends DashboardFragment
return; return;
} }
// To prevent flicker, hides secondary users preference. // To prevent flicker, hides non-current users preference.
// onReceivedSizes will set it visible for private storage. // onReceivedSizes will set it visible for private storage.
setSecondaryUsersVisible(false); setNonCurrentUsersVisible(false);
if (!mSelectedStorageEntry.isMounted()) { if (!mSelectedStorageEntry.isMounted()) {
// Set null volume to hide category stats. // Set null volume to hide category stats.
@@ -150,8 +154,8 @@ public class StorageCategoryFragment extends DashboardFragment
if (mSelectedStorageEntry != null) { if (mSelectedStorageEntry != null) {
refreshUi(mSelectedStorageEntry); refreshUi(mSelectedStorageEntry);
} }
updateSecondaryUserControllers(mSecondaryUsers, mAppsResult); updateNonCurrentUserControllers(mNonCurrentUsers, mAppsResult);
setSecondaryUsersVisible(true); setNonCurrentUsersVisible(true);
} }
} }
@@ -217,17 +221,13 @@ public class StorageCategoryFragment extends DashboardFragment
// Cache total size infor and used size info // Cache total size infor and used size info
mStorageCacheHelper mStorageCacheHelper
.cacheTotalSizeAndTotalUsedSize(mStorageInfo.totalBytes, privateUsedBytes); .cacheTotalSizeAndTotalUsedSize(mStorageInfo.totalBytes, privateUsedBytes);
for (int i = 0, size = mSecondaryUsers.size(); i < size; i++) { for (NonCurrentUserController userController : mNonCurrentUsers) {
final AbstractPreferenceController controller = mSecondaryUsers.get(i); userController.setTotalSize(mStorageInfo.totalBytes);
if (controller instanceof SecondaryUserController) {
SecondaryUserController userController = (SecondaryUserController) controller;
userController.setTotalSize(mStorageInfo.totalBytes);
}
} }
mPreferenceController.onLoadFinished(mAppsResult, mUserId); mPreferenceController.onLoadFinished(mAppsResult, mUserId);
updateSecondaryUserControllers(mSecondaryUsers, mAppsResult); updateNonCurrentUserControllers(mNonCurrentUsers, mAppsResult);
setSecondaryUsersVisible(true); setNonCurrentUsersVisible(true);
} }
@Override @Override
@@ -253,20 +253,18 @@ public class StorageCategoryFragment extends DashboardFragment
null /* volume */, new StorageManagerVolumeProvider(sm), mIsWorkProfile); null /* volume */, new StorageManagerVolumeProvider(sm), mIsWorkProfile);
controllers.add(mPreferenceController); controllers.add(mPreferenceController);
mSecondaryUsers = SecondaryUserController.getSecondaryUserControllers(context, mNonCurrentUsers = mIsWorkProfile ? EMPTY_LIST :
mUserManager, mIsWorkProfile /* isWorkProfileOnly */); NonCurrentUserController.getNonCurrentUserControllers(context, mUserManager);
controllers.addAll(mSecondaryUsers); controllers.addAll(mNonCurrentUsers);
return controllers; return controllers;
} }
/** /**
* Updates the secondary user controller sizes. * Updates the non-current user controller sizes.
*/ */
private void updateSecondaryUserControllers(List<AbstractPreferenceController> controllers, private void updateNonCurrentUserControllers(List<NonCurrentUserController> controllers,
SparseArray<StorageAsyncLoader.StorageResult> stats) { SparseArray<StorageAsyncLoader.StorageResult> stats) {
for (int i = 0, size = controllers.size(); i < size; i++) { for (AbstractPreferenceController controller : controllers) {
final AbstractPreferenceController controller = controllers.get(i);
if (controller instanceof StorageAsyncLoader.ResultHandler) { if (controller instanceof StorageAsyncLoader.ResultHandler) {
StorageAsyncLoader.ResultHandler userController = StorageAsyncLoader.ResultHandler userController =
(StorageAsyncLoader.ResultHandler) controller; (StorageAsyncLoader.ResultHandler) controller;
@@ -296,6 +294,15 @@ public class StorageCategoryFragment extends DashboardFragment
public void onLoaderReset(Loader<SparseArray<StorageAsyncLoader.StorageResult>> loader) { public void onLoaderReset(Loader<SparseArray<StorageAsyncLoader.StorageResult>> loader) {
} }
@Override
public void displayResourceTilesToScreen(PreferenceScreen screen) {
final PreferenceGroup group = screen.findPreference(TARGET_PREFERENCE_GROUP_KEY);
if (mNonCurrentUsers.isEmpty()) {
screen.removePreference(group);
}
super.displayResourceTilesToScreen(screen);
}
@VisibleForTesting @VisibleForTesting
public PrivateStorageInfo getPrivateStorageInfo() { public PrivateStorageInfo getPrivateStorageInfo() {
return mStorageInfo; return mStorageInfo;
@@ -335,13 +342,9 @@ public class StorageCategoryFragment extends DashboardFragment
.isQuotaSupported(mSelectedStorageEntry.getFsUuid()); .isQuotaSupported(mSelectedStorageEntry.getFsUuid());
} }
private void setSecondaryUsersVisible(boolean visible) { private void setNonCurrentUsersVisible(boolean visible) {
final Optional<SecondaryUserController> secondaryUserController = mSecondaryUsers.stream() if (!mNonCurrentUsers.isEmpty()) {
.filter(controller -> controller instanceof SecondaryUserController) mNonCurrentUsers.get(0).setPreferenceGroupVisible(visible);
.map(controller -> (SecondaryUserController) controller)
.findAny();
if (secondaryUserController.isPresent()) {
secondaryUserController.get().setPreferenceGroupVisible(visible);
} }
} }
@@ -361,7 +364,7 @@ public class StorageCategoryFragment extends DashboardFragment
@Override @Override
public void onLoadFinished( public void onLoadFinished(
Loader<SparseArray<Drawable>> loader, SparseArray<Drawable> data) { Loader<SparseArray<Drawable>> loader, SparseArray<Drawable> data) {
mSecondaryUsers mNonCurrentUsers
.stream() .stream()
.filter(controller -> controller instanceof UserIconLoader.UserIconHandler) .filter(controller -> controller instanceof UserIconLoader.UserIconHandler)
.forEach( .forEach(

View File

@@ -32,11 +32,12 @@ import android.os.storage.VolumeRecord;
import android.provider.SearchIndexableResource; import android.provider.SearchIndexableResource;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.View;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.loader.app.LoaderManager; import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader; import androidx.loader.content.Loader;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.Utils; import com.android.settings.Utils;
@@ -44,7 +45,7 @@ import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.deviceinfo.storage.AutomaticStorageManagementSwitchPreferenceController; import com.android.settings.deviceinfo.storage.AutomaticStorageManagementSwitchPreferenceController;
import com.android.settings.deviceinfo.storage.DiskInitFragment; import com.android.settings.deviceinfo.storage.DiskInitFragment;
import com.android.settings.deviceinfo.storage.ManageStoragePreferenceController; import com.android.settings.deviceinfo.storage.ManageStoragePreferenceController;
import com.android.settings.deviceinfo.storage.SecondaryUserController; import com.android.settings.deviceinfo.storage.NonCurrentUserController;
import com.android.settings.deviceinfo.storage.StorageAsyncLoader; import com.android.settings.deviceinfo.storage.StorageAsyncLoader;
import com.android.settings.deviceinfo.storage.StorageCacheHelper; import com.android.settings.deviceinfo.storage.StorageCacheHelper;
import com.android.settings.deviceinfo.storage.StorageEntry; import com.android.settings.deviceinfo.storage.StorageEntry;
@@ -64,7 +65,6 @@ import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional;
/** /**
* Storage Settings main UI is composed by 3 fragments: * Storage Settings main UI is composed by 3 fragments:
@@ -86,6 +86,7 @@ public class StorageDashboardFragment extends DashboardFragment
private static final String TAG = "StorageDashboardFrag"; private static final String TAG = "StorageDashboardFrag";
private static final String SUMMARY_PREF_KEY = "storage_summary"; private static final String SUMMARY_PREF_KEY = "storage_summary";
private static final String SELECTED_STORAGE_ENTRY_KEY = "selected_storage_entry_key"; private static final String SELECTED_STORAGE_ENTRY_KEY = "selected_storage_entry_key";
private static final String TARGET_PREFERENCE_GROUP_KEY = "pref_non_current_users";
private static final int STORAGE_JOB_ID = 0; private static final int STORAGE_JOB_ID = 0;
private static final int ICON_JOB_ID = 1; private static final int ICON_JOB_ID = 1;
private static final int VOLUME_SIZE_JOB_ID = 2; private static final int VOLUME_SIZE_JOB_ID = 2;
@@ -101,7 +102,7 @@ public class StorageDashboardFragment extends DashboardFragment
private VolumeOptionMenuController mOptionMenuController; private VolumeOptionMenuController mOptionMenuController;
private StorageSelectionPreferenceController mStorageSelectionController; private StorageSelectionPreferenceController mStorageSelectionController;
private StorageUsageProgressBarPreferenceController mStorageUsageProgressBarController; private StorageUsageProgressBarPreferenceController mStorageUsageProgressBarController;
private List<AbstractPreferenceController> mSecondaryUsers; private List<NonCurrentUserController> mNonCurrentUsers;
private boolean mIsWorkProfile; private boolean mIsWorkProfile;
private int mUserId; private int mUserId;
private boolean mIsLoadedFromCache; private boolean mIsLoadedFromCache;
@@ -232,9 +233,9 @@ public class StorageDashboardFragment extends DashboardFragment
mOptionMenuController.setSelectedStorageEntry(mSelectedStorageEntry); mOptionMenuController.setSelectedStorageEntry(mSelectedStorageEntry);
getActivity().invalidateOptionsMenu(); getActivity().invalidateOptionsMenu();
// To prevent flicker, hides secondary users preference. // To prevent flicker, hides non-current users preference.
// onReceivedSizes will set it visible for private storage. // onReceivedSizes will set it visible for private storage.
setSecondaryUsersVisible(false); setNonCurrentUsersVisible(false);
if (!mSelectedStorageEntry.isMounted()) { if (!mSelectedStorageEntry.isMounted()) {
// Set null volume to hide category stats. // Set null volume to hide category stats.
@@ -254,7 +255,7 @@ public class StorageDashboardFragment extends DashboardFragment
mAppsResult = null; mAppsResult = null;
// Hide the loading spinner if there is cached data. // Hide the loading spinner if there is cached data.
if (mStorageCacheHelper.hasCachedSizeInfo()) { if (mStorageCacheHelper.hasCachedSizeInfo()) {
//TODO(b/220259287): apply cache mechanism to secondary user //TODO(b/220259287): apply cache mechanism to non-current user
mPreferenceController.onLoadFinished(mAppsResult, mUserId); mPreferenceController.onLoadFinished(mAppsResult, mUserId);
} else { } else {
maybeSetLoading(isQuotaSupported()); maybeSetLoading(isQuotaSupported());
@@ -297,8 +298,8 @@ public class StorageDashboardFragment extends DashboardFragment
mStorageEntries.addAll( mStorageEntries.addAll(
StorageUtils.getAllStorageEntries(getContext(), mStorageManager)); StorageUtils.getAllStorageEntries(getContext(), mStorageManager));
refreshUi(); refreshUi();
updateSecondaryUserControllers(mSecondaryUsers, mAppsResult); updateNonCurrentUserControllers(mNonCurrentUsers, mAppsResult);
setSecondaryUsersVisible(true); setNonCurrentUsersVisible(true);
} }
} }
@@ -393,17 +394,13 @@ public class StorageDashboardFragment extends DashboardFragment
// Cache total size and used size // Cache total size and used size
mStorageCacheHelper mStorageCacheHelper
.cacheTotalSizeAndTotalUsedSize(mStorageInfo.totalBytes, privateUsedBytes); .cacheTotalSizeAndTotalUsedSize(mStorageInfo.totalBytes, privateUsedBytes);
for (int i = 0, size = mSecondaryUsers.size(); i < size; i++) { for (NonCurrentUserController userController : mNonCurrentUsers) {
final AbstractPreferenceController controller = mSecondaryUsers.get(i); userController.setTotalSize(mStorageInfo.totalBytes);
if (controller instanceof SecondaryUserController) {
SecondaryUserController userController = (SecondaryUserController) controller;
userController.setTotalSize(mStorageInfo.totalBytes);
}
} }
mPreferenceController.onLoadFinished(mAppsResult, mUserId); mPreferenceController.onLoadFinished(mAppsResult, mUserId);
updateSecondaryUserControllers(mSecondaryUsers, mAppsResult); updateNonCurrentUserControllers(mNonCurrentUsers, mAppsResult);
setSecondaryUsersVisible(true); setNonCurrentUsersVisible(true);
} }
@Override @Override
@@ -429,20 +426,19 @@ public class StorageDashboardFragment extends DashboardFragment
null /* volume */, new StorageManagerVolumeProvider(sm), mIsWorkProfile); null /* volume */, new StorageManagerVolumeProvider(sm), mIsWorkProfile);
controllers.add(mPreferenceController); controllers.add(mPreferenceController);
mSecondaryUsers = SecondaryUserController.getSecondaryUserControllers(context, mNonCurrentUsers = NonCurrentUserController.getNonCurrentUserControllers(context,
mUserManager, mIsWorkProfile /* isWorkProfileOnly */); mUserManager);
controllers.addAll(mSecondaryUsers); controllers.addAll(mNonCurrentUsers);
return controllers; return controllers;
} }
/** /**
* Updates the secondary user controller sizes. * Updates the non-current user controller sizes.
*/ */
private void updateSecondaryUserControllers(List<AbstractPreferenceController> controllers, private void updateNonCurrentUserControllers(List<NonCurrentUserController> controllers,
SparseArray<StorageAsyncLoader.StorageResult> stats) { SparseArray<StorageAsyncLoader.StorageResult> stats) {
for (int i = 0, size = controllers.size(); i < size; i++) { for (AbstractPreferenceController controller : controllers) {
final AbstractPreferenceController controller = controllers.get(i);
if (controller instanceof StorageAsyncLoader.ResultHandler) { if (controller instanceof StorageAsyncLoader.ResultHandler) {
StorageAsyncLoader.ResultHandler userController = StorageAsyncLoader.ResultHandler userController =
(StorageAsyncLoader.ResultHandler) controller; (StorageAsyncLoader.ResultHandler) controller;
@@ -473,8 +469,8 @@ public class StorageDashboardFragment extends DashboardFragment
controllers.add(new StorageItemPreferenceController(context, null /* host */, controllers.add(new StorageItemPreferenceController(context, null /* host */,
null /* volume */, new StorageManagerVolumeProvider(sm), null /* volume */, new StorageManagerVolumeProvider(sm),
false /* isWorkProfile */)); false /* isWorkProfile */));
controllers.addAll(SecondaryUserController.getSecondaryUserControllers( controllers.addAll(NonCurrentUserController.getNonCurrentUserControllers(
context, userManager, false /* isWorkProfileOnly */)); context, userManager));
return controllers; return controllers;
} }
@@ -501,6 +497,16 @@ public class StorageDashboardFragment extends DashboardFragment
public void onLoaderReset(Loader<SparseArray<StorageAsyncLoader.StorageResult>> loader) { public void onLoaderReset(Loader<SparseArray<StorageAsyncLoader.StorageResult>> loader) {
} }
@Override
public void displayResourceTilesToScreen(PreferenceScreen screen) {
final PreferenceGroup group = screen.findPreference(TARGET_PREFERENCE_GROUP_KEY);
if (mNonCurrentUsers.isEmpty()) {
screen.removePreference(group);
}
super.displayResourceTilesToScreen(screen);
}
@VisibleForTesting @VisibleForTesting
public PrivateStorageInfo getPrivateStorageInfo() { public PrivateStorageInfo getPrivateStorageInfo() {
return mStorageInfo; return mStorageInfo;
@@ -540,13 +546,9 @@ public class StorageDashboardFragment extends DashboardFragment
.isQuotaSupported(mSelectedStorageEntry.getFsUuid()); .isQuotaSupported(mSelectedStorageEntry.getFsUuid());
} }
private void setSecondaryUsersVisible(boolean visible) { private void setNonCurrentUsersVisible(boolean visible) {
final Optional<SecondaryUserController> secondaryUserController = mSecondaryUsers.stream() if (!mNonCurrentUsers.isEmpty()) {
.filter(controller -> controller instanceof SecondaryUserController) mNonCurrentUsers.get(0).setPreferenceGroupVisible(visible);
.map(controller -> (SecondaryUserController) controller)
.findAny();
if (secondaryUserController.isPresent()) {
secondaryUserController.get().setPreferenceGroupVisible(visible);
} }
} }
@@ -566,7 +568,7 @@ public class StorageDashboardFragment extends DashboardFragment
@Override @Override
public void onLoadFinished( public void onLoadFinished(
Loader<SparseArray<Drawable>> loader, SparseArray<Drawable> data) { Loader<SparseArray<Drawable>> loader, SparseArray<Drawable> data) {
mSecondaryUsers mNonCurrentUsers
.stream() .stream()
.filter(controller -> controller instanceof UserIconLoader.UserIconHandler) .filter(controller -> controller instanceof UserIconLoader.UserIconHandler)
.forEach( .forEach(

View File

@@ -16,6 +16,7 @@
package com.android.settings.deviceinfo.storage; package com.android.settings.deviceinfo.storage;
import android.app.ActivityManager;
import android.content.Context; import android.content.Context;
import android.content.pm.UserInfo; import android.content.pm.UserInfo;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
@@ -28,7 +29,6 @@ import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
import com.android.settings.Utils;
import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.deviceinfo.StorageItemPreference; import com.android.settings.deviceinfo.StorageItemPreference;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
@@ -37,14 +37,14 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* SecondaryUserController controls the preferences on the Storage screen which had to do with * NonCurrentUserController controls the preferences on the Storage screen which had to do with
* secondary users. * other users.
*/ */
public class SecondaryUserController extends AbstractPreferenceController implements public class NonCurrentUserController extends AbstractPreferenceController implements
PreferenceControllerMixin, StorageAsyncLoader.ResultHandler, PreferenceControllerMixin, StorageAsyncLoader.ResultHandler,
UserIconLoader.UserIconHandler { UserIconLoader.UserIconHandler {
// PreferenceGroupKey to try to add our preference onto. // PreferenceGroupKey to try to add our preference onto.
private static final String TARGET_PREFERENCE_GROUP_KEY = "pref_secondary_users"; private static final String TARGET_PREFERENCE_GROUP_KEY = "pref_non_current_users";
private static final String PREFERENCE_KEY_BASE = "pref_user_"; private static final String PREFERENCE_KEY_BASE = "pref_user_";
private static final int SIZE_NOT_SET = -1; private static final int SIZE_NOT_SET = -1;
@@ -57,60 +57,60 @@ public class SecondaryUserController extends AbstractPreferenceController implem
private long mSize; private long mSize;
private long mTotalSizeBytes; private long mTotalSizeBytes;
private boolean mIsVisible; private boolean mIsVisible;
private int[] mProfiles;
private StorageCacheHelper mStorageCacheHelper; private StorageCacheHelper mStorageCacheHelper;
/** /**
* Adds the appropriate controllers to a controller list for handling all secondary users on * Adds the appropriate controllers to a controller list for handling all full non current
* a device. * users on a device.
* *
* @param context Context for initializing the preference controllers. * @param context Context for initializing the preference controllers.
* @param userManager UserManagerWrapper for figuring out which controllers to add. * @param userManager UserManagerWrapper for figuring out which controllers to add.
* @param isWorkProfileOnly only shows secondary users of work profile.
* (e.g., it should be true in work profile tab)
*/ */
public static List<AbstractPreferenceController> getSecondaryUserControllers( public static List<NonCurrentUserController> getNonCurrentUserControllers(
Context context, UserManager userManager, boolean isWorkProfileOnly) { Context context, UserManager userManager) {
int currentUserId = ActivityManager.getCurrentUser();
List<AbstractPreferenceController> controllers = new ArrayList<>(); List<NonCurrentUserController> controllers = new ArrayList<>();
UserInfo primaryUser = userManager.getPrimaryUser();
boolean addedUser = false;
List<UserInfo> infos = userManager.getUsers(); List<UserInfo> infos = userManager.getUsers();
for (int i = 0, size = infos.size(); i < size; i++) { for (UserInfo info : infos) {
UserInfo info = infos.get(i); if (info.id == currentUserId || info.isProfile()) {
if (info.isPrimary()) {
continue; continue;
} }
int[] profiles = userManager.getProfileIds(info.id, false /* enabledOnly */);
if (Utils.isProfileOf(primaryUser, info)) { controllers.add(new NonCurrentUserController(context, info, profiles));
continue;
}
if (isWorkProfileOnly && !info.isManagedProfile()) {
continue;
}
controllers.add(new SecondaryUserController(context, info));
addedUser = true;
}
if (!addedUser) {
controllers.add(new NoSecondaryUserController(context));
} }
return controllers; return controllers;
} }
/** /**
* Constructor for a given secondary user. * Constructor for a given non-current user.
* *
* @param context Context to initialize the underlying {@link AbstractPreferenceController}. * @param context Context to initialize the underlying {@link AbstractPreferenceController}.
* @param info {@link UserInfo} for the secondary user which this controllers covers. * @param info {@link UserInfo} for the non-current user which these controllers cover.
* @param profiles list of IDs or user and its profiles
*/ */
@VisibleForTesting @VisibleForTesting
SecondaryUserController(Context context, @NonNull UserInfo info) { NonCurrentUserController(Context context, @NonNull UserInfo info, @NonNull int[] profiles) {
super(context); super(context);
mUser = info; mUser = info;
mSize = SIZE_NOT_SET; mSize = SIZE_NOT_SET;
mStorageCacheHelper = new StorageCacheHelper(context, info.id); mStorageCacheHelper = new StorageCacheHelper(context, info.id);
mProfiles = profiles;
}
/**
* Constructor for a given non-current user.
*
* @param context Context to initialize the underlying {@link AbstractPreferenceController}.
* @param info {@link UserInfo} for the non-current user which these controllers cover.
*/
@VisibleForTesting
NonCurrentUserController(Context context, @NonNull UserInfo info) {
super(context);
mUser = info;
mSize = SIZE_NOT_SET;
mStorageCacheHelper = new StorageCacheHelper(context, info.id);
mProfiles = new int[]{info.id};
} }
@Override @Override
@@ -140,7 +140,7 @@ public class SecondaryUserController extends AbstractPreferenceController implem
} }
/** /**
* Returns the user for which this is the secondary user controller. * Returns the user for which this is the non-current user controller.
*/ */
@NonNull @NonNull
public UserInfo getUser() { public UserInfo getUser() {
@@ -169,7 +169,7 @@ public class SecondaryUserController extends AbstractPreferenceController implem
} }
/** /**
* Sets visibility of the PreferenceGroup of secondary user. * Sets visibility of the PreferenceGroup of non-current user.
* *
* @param visible Visibility of the PreferenceGroup. * @param visible Visibility of the PreferenceGroup.
*/ */
@@ -187,10 +187,15 @@ public class SecondaryUserController extends AbstractPreferenceController implem
return; return;
} }
final StorageAsyncLoader.StorageResult result = stats.get(getUser().id); final StorageAsyncLoader.StorageResult result = stats.get(getUser().id);
if (result != null) { if (result != null) {
setSize(result.externalStats.totalBytes, true /* animate */); long totalSize = 0;
for (int id : mProfiles) {
totalSize += stats.get(id).externalStats.totalBytes;
}
setSize(totalSize, true /* animate */);
// TODO(b/171758224): Update the source of size info // TODO(b/171758224): Update the source of size info
mStorageCacheHelper.cacheUsedSize(result.externalStats.totalBytes); mStorageCacheHelper.cacheUsedSize(totalSize);
} }
} }
@@ -205,31 +210,4 @@ public class SecondaryUserController extends AbstractPreferenceController implem
mStoragePreference.setIcon(mUserIcon); mStoragePreference.setIcon(mUserIcon);
} }
} }
@VisibleForTesting
static class NoSecondaryUserController extends AbstractPreferenceController implements
PreferenceControllerMixin {
public NoSecondaryUserController(Context context) {
super(context);
}
@Override
public void displayPreference(PreferenceScreen screen) {
final PreferenceGroup group = screen.findPreference(TARGET_PREFERENCE_GROUP_KEY);
if (group == null) {
return;
}
screen.removePreference(group);
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public String getPreferenceKey() {
return null;
}
}
} }

View File

@@ -26,6 +26,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.app.IActivityManager;
import android.content.Context; import android.content.Context;
import android.content.pm.UserInfo; import android.content.pm.UserInfo;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
@@ -36,10 +37,11 @@ import androidx.preference.Preference;
import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
import com.android.settings.testutils.shadow.ShadowActivityManager;
import com.android.settingslib.applications.StorageStatsSource; import com.android.settingslib.applications.StorageStatsSource;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.drawable.UserIconDrawable; import com.android.settingslib.drawable.UserIconDrawable;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -48,12 +50,14 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class SecondaryUserControllerTest { @Config(shadows = {ShadowActivityManager.class})
public class NonCurrentUserControllerTest {
private static final String TEST_NAME = "Fred"; private static final String TEST_NAME = "Fred";
private static final String TARGET_PREFERENCE_GROUP_KEY = "pref_secondary_users"; private static final String TARGET_PREFERENCE_GROUP_KEY = "pref_secondary_users";
@@ -63,18 +67,22 @@ public class SecondaryUserControllerTest {
private PreferenceScreen mScreen; private PreferenceScreen mScreen;
@Mock @Mock
private PreferenceGroup mGroup; private PreferenceGroup mGroup;
@Mock
private IActivityManager mActivityService;
private Context mContext; private Context mContext;
private SecondaryUserController mController; private NonCurrentUserController mController;
private UserInfo mPrimaryUser; private UserInfo mPrimaryUser;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application; mContext = RuntimeEnvironment.application;
mPrimaryUser = new UserInfo(); mPrimaryUser = new UserInfo();
mPrimaryUser.flags = UserInfo.FLAG_PRIMARY; mPrimaryUser.flags = UserInfo.FLAG_PRIMARY;
mController = new SecondaryUserController(mContext, mPrimaryUser); mController = new NonCurrentUserController(mContext, mPrimaryUser);
ShadowActivityManager.setService(mActivityService);
when(mScreen.getContext()).thenReturn(mContext); when(mScreen.getContext()).thenReturn(mContext);
when(mScreen.findPreference(anyString())).thenReturn(mGroup); when(mScreen.findPreference(anyString())).thenReturn(mGroup);
@@ -82,6 +90,11 @@ public class SecondaryUserControllerTest {
} }
@After
public void tearDown() {
ShadowActivityManager.setCurrentUser(mPrimaryUser.id);
}
@Test @Test
public void controllerAddsSecondaryUser() { public void controllerAddsSecondaryUser() {
mPrimaryUser.name = TEST_NAME; mPrimaryUser.name = TEST_NAME;
@@ -107,22 +120,18 @@ public class SecondaryUserControllerTest {
} }
@Test @Test
public void noSecondaryUserAddedIfNoneExist() { public void noNonCurrentUserAddedIfNoneExist() {
final ArrayList<UserInfo> userInfos = new ArrayList<>(); final ArrayList<UserInfo> userInfos = new ArrayList<>();
userInfos.add(mPrimaryUser); userInfos.add(mPrimaryUser);
when(mUserManager.getPrimaryUser()).thenReturn(mPrimaryUser); when(mUserManager.getPrimaryUser()).thenReturn(mPrimaryUser);
when(mUserManager.getUsers()).thenReturn(userInfos); when(mUserManager.getUsers()).thenReturn(userInfos);
final List<AbstractPreferenceController> controllers = final List<NonCurrentUserController> controllers =
SecondaryUserController.getSecondaryUserControllers(mContext, mUserManager, NonCurrentUserController.getNonCurrentUserControllers(mContext, mUserManager);
false /* isWorkProfileOnly */); assertThat(controllers).hasSize(0);
assertThat(controllers).hasSize(1);
// We should have the NoSecondaryUserController.
assertThat(controllers.get(0) instanceof SecondaryUserController).isFalse();
} }
@Test @Test
public void getSecondaryUserControllers_notWorkProfile_addSecondaryUserController() { public void getNonCurrentUserControllers_notWorkProfile_addNonCurrentUserController() {
final ArrayList<UserInfo> userInfos = new ArrayList<>(); final ArrayList<UserInfo> userInfos = new ArrayList<>();
final UserInfo secondaryUser = spy(new UserInfo()); final UserInfo secondaryUser = spy(new UserInfo());
secondaryUser.id = 10; secondaryUser.id = 10;
@@ -131,17 +140,16 @@ public class SecondaryUserControllerTest {
userInfos.add(mPrimaryUser); userInfos.add(mPrimaryUser);
userInfos.add(secondaryUser); userInfos.add(secondaryUser);
when(mUserManager.getPrimaryUser()).thenReturn(mPrimaryUser); when(mUserManager.getPrimaryUser()).thenReturn(mPrimaryUser);
ShadowActivityManager.setCurrentUser(secondaryUser.id);
when(mUserManager.getUsers()).thenReturn(userInfos); when(mUserManager.getUsers()).thenReturn(userInfos);
final List<AbstractPreferenceController> controllers = final List<NonCurrentUserController> controllers =
SecondaryUserController.getSecondaryUserControllers(mContext, mUserManager, NonCurrentUserController.getNonCurrentUserControllers(mContext, mUserManager);
false /* isWorkProfileOnly */);
assertThat(controllers).hasSize(1); assertThat(controllers).hasSize(1);
assertThat(controllers.get(0) instanceof SecondaryUserController).isTrue();
} }
@Test @Test
public void getSecondaryUserControllers_workProfile_addNoSecondaryUserController() { public void getNonCurrentUserControllers_workProfileOfNonCurrentUser() {
final ArrayList<UserInfo> userInfos = new ArrayList<>(); final ArrayList<UserInfo> userInfos = new ArrayList<>();
final UserInfo secondaryUser = spy(new UserInfo()); final UserInfo secondaryUser = spy(new UserInfo());
secondaryUser.id = 10; secondaryUser.id = 10;
@@ -150,56 +158,37 @@ public class SecondaryUserControllerTest {
userInfos.add(mPrimaryUser); userInfos.add(mPrimaryUser);
userInfos.add(secondaryUser); userInfos.add(secondaryUser);
when(mUserManager.getPrimaryUser()).thenReturn(mPrimaryUser); when(mUserManager.getPrimaryUser()).thenReturn(mPrimaryUser);
when(secondaryUser.isProfile()).thenReturn(true);
when(mUserManager.getUsers()).thenReturn(userInfos); when(mUserManager.getUsers()).thenReturn(userInfos);
final List<AbstractPreferenceController> controllers = final List<NonCurrentUserController> controllers =
SecondaryUserController.getSecondaryUserControllers(mContext, mUserManager, NonCurrentUserController.getNonCurrentUserControllers(mContext, mUserManager);
false /* isWorkProfileOnly */);
assertThat(controllers).hasSize(1); assertThat(controllers).hasSize(0);
assertThat(controllers.get(0) instanceof SecondaryUserController).isTrue();
} }
@Test @Test
public void getSecondaryUserControllers_notWorkProfileWorkProfileOnly_addNoSecondController() { public void profilesOfCurrentUserAreIgnored() {
final ArrayList<UserInfo> userInfos = new ArrayList<>();
final UserInfo secondaryUser = spy(new UserInfo());
secondaryUser.id = 10;
secondaryUser.profileGroupId = 101010; // this just has to be something not 0
when(secondaryUser.isManagedProfile()).thenReturn(false);
userInfos.add(mPrimaryUser);
userInfos.add(secondaryUser);
when(mUserManager.getPrimaryUser()).thenReturn(mPrimaryUser);
when(mUserManager.getUsers()).thenReturn(userInfos);
final List<AbstractPreferenceController> controllers =
SecondaryUserController.getSecondaryUserControllers(mContext, mUserManager,
true /* isWorkProfileOnly */);
assertThat(controllers).hasSize(1);
assertThat(controllers.get(0) instanceof SecondaryUserController).isFalse();
}
@Test
public void profilesOfPrimaryUserAreIgnored() {
final ArrayList<UserInfo> userInfos = new ArrayList<>(); final ArrayList<UserInfo> userInfos = new ArrayList<>();
final UserInfo secondaryUser = new UserInfo(); final UserInfo secondaryUser = new UserInfo();
secondaryUser.id = mPrimaryUser.id; secondaryUser.id = mPrimaryUser.id;
userInfos.add(mPrimaryUser); userInfos.add(mPrimaryUser);
userInfos.add(secondaryUser); userInfos.add(secondaryUser);
userInfos.add(secondaryUser);
when(mUserManager.getPrimaryUser()).thenReturn(mPrimaryUser); when(mUserManager.getPrimaryUser()).thenReturn(mPrimaryUser);
when(mUserManager.getUsers()).thenReturn(userInfos); when(mUserManager.getUsers()).thenReturn(userInfos);
final List<AbstractPreferenceController> controllers = final List<NonCurrentUserController> controllers =
SecondaryUserController.getSecondaryUserControllers(mContext, mUserManager, NonCurrentUserController.getNonCurrentUserControllers(mContext, mUserManager);
false /* isWorkProfileOnly */);
assertThat(controllers).hasSize(1); assertThat(controllers).hasSize(0);
assertThat(controllers.get(0) instanceof SecondaryUserController).isFalse();
} }
@Test @Test
public void handleResult_noStatsResult_shouldShowCachedData() { public void handleResult_noStatsResult_shouldShowCachedData() {
mPrimaryUser.name = TEST_NAME; mPrimaryUser.name = TEST_NAME;
mPrimaryUser.id = 10; mPrimaryUser.id = 10;
int[] profiles = {mPrimaryUser.id};
mController = new NonCurrentUserController(mContext, mPrimaryUser, profiles);
mController.displayPreference(mScreen); mController.displayPreference(mScreen);
final StorageAsyncLoader.StorageResult userResult = final StorageAsyncLoader.StorageResult userResult =
new StorageAsyncLoader.StorageResult(); new StorageAsyncLoader.StorageResult();
@@ -232,15 +221,12 @@ public class SecondaryUserControllerTest {
primaryUserRenamed.name = "Owner"; primaryUserRenamed.name = "Owner";
primaryUserRenamed.flags = UserInfo.FLAG_PRIMARY; primaryUserRenamed.flags = UserInfo.FLAG_PRIMARY;
userInfos.add(primaryUserRenamed); userInfos.add(primaryUserRenamed);
when(mUserManager.getPrimaryUser()).thenReturn(mPrimaryUser); ShadowActivityManager.setCurrentUser(primaryUserRenamed.id);
when(mUserManager.getUsers()).thenReturn(userInfos); when(mUserManager.getUsers()).thenReturn(userInfos);
final List<AbstractPreferenceController> controllers = final List<NonCurrentUserController> controllers =
SecondaryUserController.getSecondaryUserControllers(mContext, mUserManager, NonCurrentUserController.getNonCurrentUserControllers(mContext, mUserManager);
false /* isWorkProfileOnly */);
assertThat(controllers).hasSize(1); assertThat(controllers).hasSize(0);
// We should have the NoSecondaryUserController.
assertThat(controllers.get(0) instanceof SecondaryUserController).isFalse();
} }
@Test @Test
@@ -273,4 +259,31 @@ public class SecondaryUserControllerTest {
// Doesn't crash // Doesn't crash
} }
@Test
public void getNonCurrentUserControllers_switchUsers() {
final ArrayList<UserInfo> userInfo = new ArrayList<>();
final UserInfo secondaryUser = spy(new UserInfo());
secondaryUser.id = 10;
final UserInfo secondaryUser1 = spy(new UserInfo());
secondaryUser1.id = 11;
userInfo.add(mPrimaryUser);
userInfo.add(secondaryUser);
userInfo.add(secondaryUser1);
when(mUserManager.getPrimaryUser()).thenReturn(mPrimaryUser);
when(mUserManager.getUsers()).thenReturn(userInfo);
List<NonCurrentUserController> controllers =
NonCurrentUserController.getNonCurrentUserControllers(mContext, mUserManager);
assertThat(controllers).hasSize(2);
assertThat(controllers.get(0).getUser().id == secondaryUser.id).isTrue();
ShadowActivityManager.setCurrentUser(secondaryUser.id);
when(mUserManager.getUsers()).thenReturn(userInfo);
controllers =
NonCurrentUserController.getNonCurrentUserControllers(mContext, mUserManager);
assertThat(controllers).hasSize(2);
assertThat(controllers.get(0).getUser().id == mPrimaryUser.id).isTrue();
}
} }