Manish Singh
2023-09-28 12:02:21 +01:00
parent a223c7644e
commit 6efc455f2c
32 changed files with 954 additions and 162 deletions

View File

@@ -6180,6 +6180,8 @@
<string name="account_settings_menu_auto_sync_personal">Auto-sync personal data</string>
<!-- Title for menu option to enable global auto-sync of work account data [CHAR LIMIT=30] -->
<string name="account_settings_menu_auto_sync_work">Auto-sync work data</string>
<!-- Title for menu option to enable global auto-sync of private account data [CHAR LIMIT=30] -->
<string name="account_settings_menu_auto_sync_private">Auto-sync private data</string>
<!-- Title for option to change data usage cycle day. [CHAR LIMIT=32] -->
<string name="data_usage_change_cycle">Change cycle\u2026</string>

View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 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.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="user_and_account_settings_screen"
android:title="@string/account_dashboard_title"
settings:keywords="@string/keywords_accounts">
<PreferenceCategory
android:key="passwords_category"
android:order="10"
android:persistent="false"
android:title="@string/autofill_passwords"
settings:controller="com.android.settings.applications.autofill.PasswordsPreferenceController"
settings:keywords="@string/autofill_keywords" />
<PreferenceCategory
android:key="default_service_category"
android:order="20"
android:title="@string/autofill_app">
<com.android.settings.widget.GearPreference
android:fragment="com.android.settings.applications.defaultapps.DefaultAutofillPicker"
android:key="default_autofill_private"
android:title="@string/autofill_app"
settings:keywords="@string/autofill_keywords">
<extra
android:name="for_work"
android:value="false" />
</com.android.settings.widget.GearPreference>
</PreferenceCategory>
<PreferenceCategory
android:key="dashboard_tile_placeholder"
android:order="130"/>
<SwitchPreference
android:key="auto_sync_account_data"
android:title="@string/auto_sync_account_title"
android:summary="@string/auto_sync_account_summary"
android:order="200"
settings:allowDividerAbove="true"/>
<SwitchPreference
android:key="auto_sync_private_account_data"
android:title="@string/account_settings_menu_auto_sync_private"
android:summary="@string/auto_sync_account_summary"
android:order="210"/>
</PreferenceScreen>

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 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.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="user_and_account_settings_screen"
android:title="@string/account_dashboard_title"
settings:keywords="@string/keywords_accounts">
<PreferenceCategory
android:key="default_service_category"
android:order="10"
android:title="@string/credman_chosen_app_title">
<com.android.settings.widget.GearPreference
android:fragment="com.android.settings.applications.credentials.DefaultCombinedPickerPrivate"
android:key="default_credman_autofill_private"
android:title="@string/credman_chosen_app_title"
settings:searchable="false">
settings:keywords="@string/credman_autofill_keywords">
<extra
android:name="for_work"
android:value="false" />
</com.android.settings.widget.GearPreference>
</PreferenceCategory>
<PreferenceCategory
android:key="credman_category"
android:order="20"
android:persistent="false"
android:title="@string/credman_credentials"
settings:controller="com.android.settings.applications.credentials.CredentialManagerPreferenceController"
settings:keywords="@string/credman_keywords" />
<PreferenceCategory
android:key="dashboard_tile_placeholder"
android:order="130"/>
<SwitchPreference
android:key="auto_sync_account_data"
android:title="@string/auto_sync_account_title"
android:summary="@string/auto_sync_account_summary"
android:order="200"
settings:allowDividerAbove="true"/>
<SwitchPreference
android:key="auto_sync_private_account_data"
android:title="@string/account_settings_menu_auto_sync_private"
android:summary="@string/auto_sync_account_summary"
android:order="210"/>
</PreferenceScreen>

View File

@@ -18,6 +18,9 @@ package com.android.settings;
import static android.content.Intent.EXTRA_USER;
import static android.content.Intent.EXTRA_USER_ID;
import static android.os.UserManager.USER_TYPE_FULL_SYSTEM;
import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE;
import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
@@ -63,6 +66,7 @@ import android.os.BatteryManager;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Flags;
import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.RemoteException;
@@ -111,6 +115,7 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.dashboard.profileselector.ProfileFragmentBridge;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment.ProfileType;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settingslib.widget.ActionBarShadowController;
import com.android.settingslib.widget.AdaptiveIcon;
@@ -118,6 +123,7 @@ import com.android.settingslib.widget.AdaptiveIcon;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
public final class Utils extends com.android.settingslib.Utils {
@@ -440,6 +446,38 @@ public final class Utils extends com.android.settingslib.Utils {
return null;
}
/**
* Returns the profile of userType of the current user or {@code null} if none is found or a
* profile exists, but it is disabled.
*/
@Nullable
public static UserHandle getProfileOfType(
@NonNull UserManager userManager, @ProfileType int userType) {
final List<UserHandle> userProfiles = userManager.getUserProfiles();
String umUserType = getUmUserType(userType);
for (UserHandle profile : userProfiles) {
if (profile.getIdentifier() == UserHandle.myUserId()) {
continue;
}
final UserInfo userInfo = userManager.getUserInfo(profile.getIdentifier());
if (Objects.equals(umUserType, userInfo.userType)) {
return profile;
}
}
return null;
}
private static String getUmUserType(@ProfileType int userType) throws IllegalArgumentException {
if (userType == ProfileType.WORK) {
return USER_TYPE_PROFILE_MANAGED;
} else if (userType == ProfileType.PRIVATE) {
return USER_TYPE_PROFILE_PRIVATE;
} else if (userType == ProfileType.PERSONAL) {
return USER_TYPE_FULL_SYSTEM;
}
throw new IllegalArgumentException("Cannot get user type for ALL types");
}
/**
* Returns the managed profile of the current user or {@code null} if none is found. Unlike
* {@link #getManagedProfile} this method returns enabled and disabled managed profiles.
@@ -479,15 +517,20 @@ public final class Utils extends com.android.settingslib.Utils {
return UserHandle.USER_NULL;
}
/** Returns user ID of current user, throws IllegalStateException if it's not available. */
public static int getCurrentUserId(UserManager userManager, boolean isWorkProfile)
throws IllegalStateException {
if (isWorkProfile) {
final UserHandle managedUserHandle = getManagedProfile(userManager);
if (managedUserHandle == null) {
throw new IllegalStateException("Work profile user ID is not available.");
/**
* Returns user ID of the user of specified type under the current context, throws
* IllegalStateException if it's not available.
*/
public static int getCurrentUserIdOfType(
@NonNull UserManager userManager,
@ProfileType int userType) throws IllegalStateException {
if (userType != ProfileType.PERSONAL) {
final UserHandle userHandle = getProfileOfType(userManager, userType);
if (userHandle == null) {
throw new IllegalStateException("User ID of requested profile type is not "
+ "available.");
}
return managedUserHandle.getIdentifier();
return userHandle.getIdentifier();
}
return UserHandle.myUserId();
}
@@ -1223,8 +1266,10 @@ public final class Utils extends com.android.settingslib.Utils {
List<UserHandle> profiles = userManager.getUserProfiles();
for (UserHandle userHandle : profiles) {
UserProperties userProperties = userManager.getUserProperties(userHandle);
if (userProperties.getShowInSettings()
== UserProperties.SHOW_IN_SETTINGS_SEPARATE) {
if (userProperties.getShowInSettings() == UserProperties.SHOW_IN_SETTINGS_SEPARATE) {
if (Flags.allowPrivateProfile() && userProperties.getHideInSettingsInQuietMode()) {
return !userManager.isQuietModeEnabled(userHandle);
}
return true;
}
}

View File

@@ -31,14 +31,17 @@ import com.android.settings.R;
import com.android.settings.applications.autofill.PasswordsPreferenceController;
import com.android.settings.applications.credentials.CredentialManagerPreferenceController;
import com.android.settings.applications.credentials.DefaultCombinedPreferenceController;
import com.android.settings.applications.credentials.DefaultPrivateCombinedPreferenceController;
import com.android.settings.applications.credentials.DefaultWorkCombinedPreferenceController;
import com.android.settings.applications.defaultapps.DefaultAutofillPreferenceController;
import com.android.settings.applications.defaultapps.DefaultPrivateAutofillPreferenceController;
import com.android.settings.applications.defaultapps.DefaultWorkAutofillPreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.users.AutoSyncDataPreferenceController;
import com.android.settings.users.AutoSyncPersonalDataPreferenceController;
import com.android.settings.users.AutoSyncPrivateDataPreferenceController;
import com.android.settings.users.AutoSyncWorkDataPreferenceController;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.search.SearchIndexable;
@@ -111,9 +114,11 @@ public class AccountDashboardFragment extends DashboardFragment {
if (CredentialManager.isServiceEnabled(context)) {
controllers.add(new DefaultCombinedPreferenceController(context));
controllers.add(new DefaultWorkCombinedPreferenceController(context));
controllers.add(new DefaultPrivateCombinedPreferenceController(context));
} else {
controllers.add(new DefaultAutofillPreferenceController(context));
controllers.add(new DefaultWorkAutofillPreferenceController(context));
controllers.add(new DefaultPrivateAutofillPreferenceController(context));
}
}
@@ -132,6 +137,7 @@ public class AccountDashboardFragment extends DashboardFragment {
controllers.add(new AutoSyncDataPreferenceController(context, parent));
controllers.add(new AutoSyncPersonalDataPreferenceController(context, parent));
controllers.add(new AutoSyncWorkDataPreferenceController(context, parent));
controllers.add(new AutoSyncPrivateDataPreferenceController(context, parent));
}
private static int getPreferenceLayoutResId(Context context) {

View File

@@ -296,14 +296,15 @@ public class AccountPreferenceController extends AbstractPreferenceController
updateProfileUi(userInfo);
} else {
List<UserInfo> profiles = mUm.getProfiles(UserHandle.myUserId());
final int profilesCount = profiles.size();
for (int i = 0; i < profilesCount; i++) {
if (profiles.get(i).isManagedProfile()
&& (mType & ProfileSelectFragment.ProfileType.WORK) != 0) {
updateProfileUi(profiles.get(i));
} else if (!profiles.get(i).isManagedProfile()
&& (mType & ProfileSelectFragment.ProfileType.PERSONAL) != 0) {
updateProfileUi(profiles.get(i));
for (UserInfo profile : profiles) {
if ((profile.isManagedProfile()
&& (mType & ProfileSelectFragment.ProfileType.WORK) != 0)
|| (profile.isPrivateProfile()
&& (mType & ProfileSelectFragment.ProfileType.PRIVATE) != 0)
|| (!profile.isManagedProfile()
&& !profile.isPrivateProfile()
&& (mType & ProfileSelectFragment.ProfileType.PERSONAL) != 0)) {
updateProfileUi(profile);
}
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright (C) 2023 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.settings.accounts;
import static android.provider.Settings.EXTRA_AUTHORITIES;
import static com.android.settings.accounts.AccountDashboardFragment.buildAutofillPreferenceControllers;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.credentials.CredentialManager;
import com.android.settings.R;
import com.android.settings.applications.autofill.PasswordsPreferenceController;
import com.android.settings.applications.credentials.CredentialManagerPreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
import com.android.settings.users.AutoSyncDataPreferenceController;
import com.android.settings.users.AutoSyncPrivateDataPreferenceController;
import com.android.settingslib.core.AbstractPreferenceController;
import java.util.ArrayList;
import java.util.List;
public class AccountPrivateDashboardFragment extends DashboardFragment {
private static final String TAG = "AccountPrivateFrag";
@Override
public int getMetricsCategory() {
return SettingsEnums.ACCOUNT_PRIVATE;
}
@Override
protected String getLogTag() {
return TAG;
}
@Override
protected int getPreferenceScreenResId() {
if (this.getContext() != null && CredentialManager.isServiceEnabled(this.getContext())) {
return R.xml.accounts_private_dashboard_settings_credman;
}
return R.xml.accounts_private_dashboard_settings;
}
@Override
public int getHelpResource() {
return R.string.help_url_user_and_account_dashboard;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (CredentialManager.isServiceEnabled(context)) {
CredentialManagerPreferenceController cmpp =
use(CredentialManagerPreferenceController.class);
CredentialManagerPreferenceController.Delegate delegate =
new CredentialManagerPreferenceController.Delegate() {
public void setActivityResult(int resultCode) {
getActivity().setResult(resultCode);
}
public void forceDelegateRefresh() {
forceUpdatePreferences();
}
};
cmpp.init(this, getFragmentManager(), getIntent(), delegate, /*isWorkProfile=*/false);
} else {
getSettingsLifecycle().addObserver(use(PasswordsPreferenceController.class));
}
}
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
buildAutofillPreferenceControllers(context, controllers);
final String[] authorities = getIntent().getStringArrayExtra(EXTRA_AUTHORITIES);
buildAccountPreferenceControllers(context, authorities, controllers);
return controllers;
}
private void buildAccountPreferenceControllers(
Context context,
String[] authorities,
List<AbstractPreferenceController> controllers) {
final AccountPreferenceController accountPrefController =
new AccountPreferenceController(
context,
this,
authorities,
ProfileSelectFragment.ProfileType.PRIVATE);
controllers.add(accountPrefController);
controllers.add(new AutoSyncDataPreferenceController(context, this));
controllers.add(new AutoSyncPrivateDataPreferenceController(context, this));
}
}

View File

@@ -17,6 +17,7 @@
package com.android.settings.applications.autofill;
import static android.app.admin.DevicePolicyResources.Strings.Settings.AUTO_SYNC_PERSONAL_DATA;
import static android.app.admin.DevicePolicyResources.Strings.Settings.AUTO_SYNC_PRIVATE_DATA;
import static android.app.admin.DevicePolicyResources.Strings.Settings.AUTO_SYNC_WORK_DATA;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.service.autofill.AutofillService.EXTRA_RESULT;
@@ -122,6 +123,8 @@ public class PasswordsPreferenceController extends BasePreferenceController
AUTO_SYNC_PERSONAL_DATA, R.string.account_settings_menu_auto_sync_personal);
replaceEnterpriseStringTitle(screen, "auto_sync_work_account_data",
AUTO_SYNC_WORK_DATA, R.string.account_settings_menu_auto_sync_work);
replaceEnterpriseStringTitle(screen, "auto_sync_private_account_data",
AUTO_SYNC_PRIVATE_DATA, R.string.account_settings_menu_auto_sync_private);
}
private void addPasswordPreferences(

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2023 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.settings.applications.credentials;
import android.os.UserManager;
import com.android.settings.Utils;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment.ProfileType;
public class DefaultCombinedPickerPrivate extends DefaultCombinedPicker {
@Override
protected int getUser() {
UserManager userManager = getContext().getSystemService(UserManager.class);
return Utils.getCurrentUserIdOfType(userManager, ProfileType.PRIVATE);
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2023 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.settings.applications.credentials
import android.content.Context
import android.content.Intent
import android.os.UserHandle
import com.android.settings.Utils
import com.android.settings.dashboard.profileselector.ProfileSelectFragment
import com.android.settingslib.applications.DefaultAppInfo
class DefaultPrivateCombinedPreferenceController(context: Context?) : DefaultCombinedPreferenceController(context) {
private val userHandle: UserHandle? =
Utils.getProfileOfType(mUserManager, ProfileSelectFragment.ProfileType.PRIVATE)
override fun isAvailable(): Boolean {
return if (userHandle == null) {
false
} else super.isAvailable()
}
override fun getPreferenceKey(): String {
return "default_credman_autofill_private"
}
override fun getSettingIntent(info: DefaultAppInfo ?): Intent ? {
if (info == null) {
return null
}
return userHandle?.let { handle ->
AutofillSettingIntentProvider(mContext, handle.identifier, info.key).intent
} ?: null
}
override fun startActivity(intent: Intent) {
userHandle?.let { handle ->
mContext.startActivityAsUser(intent, handle)
}
}
override fun getUser(): Int {
return userHandle?.identifier ?: UserHandle.myUserId()
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2023 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.settings.applications.defaultapps
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.UserHandle
import android.provider.Settings
import android.text.TextUtils
import com.android.settings.Utils
import com.android.settings.dashboard.profileselector.ProfileSelectFragment
import com.android.settingslib.applications.DefaultAppInfo
class DefaultPrivateAutofillPreferenceController(context: Context?) : DefaultAutofillPreferenceController(context) {
private val userHandle: UserHandle? = Utils
.getProfileOfType(mUserManager, ProfileSelectFragment.ProfileType.PRIVATE)
override fun isAvailable(): Boolean {
return if (userHandle == null) {
false
} else super.isAvailable()
}
override fun getPreferenceKey(): String {
return "default_autofill_private"
}
override fun getDefaultAppInfo(): DefaultAppInfo ? {
val flattenComponent = userHandle?.let { handle ->
Settings.Secure.getStringForUser(
mContext.contentResolver,
DefaultAutofillPicker.SETTING,
handle.identifier
)
}
return if (!flattenComponent.isNullOrEmpty()) {
userHandle?.let {
DefaultAppInfo(
mContext,
mPackageManager,
it.identifier,
ComponentName.unflattenFromString(flattenComponent))
}
} else null
}
override fun startActivity(intent: Intent) {
if (userHandle == null) {
mContext.startActivityAsUser(intent, UserHandle.CURRENT)
} else mContext.startActivityAsUser(intent, userHandle)
}
}

View File

@@ -15,10 +15,12 @@
*/
package com.android.settings.dashboard.profileselector;
import androidx.fragment.app.Fragment;
import com.android.settings.R;
import com.android.settings.accounts.AccountPersonalDashboardFragment;
import com.android.settings.accounts.AccountPrivateDashboardFragment;
import com.android.settings.accounts.AccountWorkProfileDashboardFragment;
/**
@@ -28,10 +30,12 @@ public class ProfileSelectAccountFragment extends ProfileSelectFragment {
@Override
public Fragment[] getFragments() {
return new Fragment[] {
new AccountPersonalDashboardFragment(),
new AccountWorkProfileDashboardFragment()
};
return ProfileSelectFragment.getFragments(
getContext(),
null /* bundle */,
AccountPersonalDashboardFragment::new,
AccountWorkProfileDashboardFragment::new,
AccountPrivateDashboardFragment::new);
}
@Override

View File

@@ -17,21 +17,28 @@
package com.android.settings.dashboard.profileselector;
import static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_CATEGORY_HEADER;
import static android.app.admin.DevicePolicyResources.Strings.Settings.PRIVATE_CATEGORY_HEADER;
import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_CATEGORY_HEADER;
import static android.content.Intent.EXTRA_USER_ID;
import android.annotation.IntDef;
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.Flags;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
@@ -42,12 +49,14 @@ import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.privatespace.PrivateSpaceMaintainer;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
/**
* Base fragment class for profile settings.
@@ -77,9 +86,14 @@ public abstract class ProfileSelectFragment extends DashboardFragment {
int WORK = 1 << 1;
/**
* It is personal and work profile
* It is private profile
*/
int ALL = PERSONAL | WORK;
int PRIVATE = 1 << 2;
/**
* It is personal, work, and private profile
*/
int ALL = PERSONAL | WORK | PRIVATE;
}
/**
@@ -97,6 +111,11 @@ public abstract class ProfileSelectFragment extends DashboardFragment {
*/
public static final int WORK_TAB = 1;
/**
* Used in fragment argument with Extra key {@link SettingsActivity.EXTRA_SHOW_FRAGMENT_TAB}
*/
public static final int PRIVATE_TAB = 2;
private ViewGroup mContentView;
private ViewPager2 mViewPager;
@@ -215,12 +234,20 @@ public abstract class ProfileSelectFragment extends DashboardFragment {
if (isWorkProfile) {
return WORK_TAB;
}
UserInfo userInfo = UserManager.get(activity).getUserInfo(userId);
if (Flags.allowPrivateProfile() && userInfo != null && userInfo.isPrivateProfile()) {
return PRIVATE_TAB;
}
}
// Start intent from a specific user eg: adb shell --user 10
final int intentUser = activity.getIntent().getContentUserHint();
if (UserManager.get(activity).isManagedProfile(intentUser)) {
return WORK_TAB;
}
UserInfo userInfo = UserManager.get(activity).getUserInfo(intentUser);
if (Flags.allowPrivateProfile() && userInfo != null && userInfo.isPrivateProfile()) {
return PRIVATE_TAB;
}
return PERSONAL_TAB;
}
@@ -229,13 +256,114 @@ public abstract class ProfileSelectFragment extends DashboardFragment {
final DevicePolicyManager devicePolicyManager =
getContext().getSystemService(DevicePolicyManager.class);
if (position == WORK_TAB) {
if (Flags.allowPrivateProfile()) {
int tabForPosition =
((ViewPagerAdapter) mViewPager.getAdapter()).getTabForPosition(position);
if (tabForPosition == WORK_TAB) {
return devicePolicyManager.getResources().getString(WORK_CATEGORY_HEADER,
() -> getContext().getString(com.android.settingslib.R.string.category_work));
() -> getContext().getString(
com.android.settingslib.R.string.category_work));
}
if (tabForPosition == PRIVATE_TAB) {
return devicePolicyManager.getResources().getString(PRIVATE_CATEGORY_HEADER,
() -> getContext()
.getString(com.android.settingslib.R.string.category_private));
}
} else if (position == WORK_TAB) {
return devicePolicyManager.getResources().getString(WORK_CATEGORY_HEADER,
() -> getContext().getString(com.android.settingslib.R.string.category_work));
}
return devicePolicyManager.getResources().getString(PERSONAL_CATEGORY_HEADER,
() -> getContext().getString(com.android.settingslib.R.string.category_personal));
() -> getContext().getString(
com.android.settingslib.R.string.category_personal));
}
/** Creates fragments of passed types, and returns them in an array. */
@NonNull static Fragment[] getFragments(
Context context,
@Nullable Bundle bundle,
FragmentConstructor personalFragmentConstructor,
FragmentConstructor workFragmentConstructor,
FragmentConstructor privateFragmentConstructor) {
return getFragments(
context,
bundle,
personalFragmentConstructor,
workFragmentConstructor,
privateFragmentConstructor,
new PrivateSpaceInfoProvider() {},
new ManagedProfileInfoProvider() {});
}
/**
* Creates fragments of passed types, and returns them in an array. This overload exists only
* for helping with testing.
*/
@NonNull static Fragment[] getFragments(
Context context,
@Nullable Bundle bundle,
FragmentConstructor personalFragmentConstructor,
FragmentConstructor workFragmentConstructor,
FragmentConstructor privateFragmentConstructor,
PrivateSpaceInfoProvider privateSpaceInfoProvider,
ManagedProfileInfoProvider managedProfileInfoProvider) {
Fragment[] result = new Fragment[0];
ArrayList<Fragment> fragments = new ArrayList<>();
try {
final Bundle personalOnly = bundle != null ? bundle : new Bundle();
personalOnly.putInt(EXTRA_PROFILE, ProfileType.PERSONAL);
final Fragment personalFragment =
personalFragmentConstructor.constructAndGetFragment();
personalFragment.setArguments(personalOnly);
fragments.add(personalFragment);
if (managedProfileInfoProvider.getManagedProfile(context) != null) {
final Bundle workOnly = bundle != null ? bundle : new Bundle();
workOnly.putInt(EXTRA_PROFILE, ProfileType.WORK);
final Fragment workFragment =
workFragmentConstructor.constructAndGetFragment();
workFragment.setArguments(workOnly);
fragments.add(workFragment);
}
if (Flags.allowPrivateProfile()
&& !privateSpaceInfoProvider.isPrivateSpaceLocked(context)) {
final Bundle privateOnly = bundle != null ? bundle : new Bundle();
privateOnly.putInt(EXTRA_PROFILE, ProfileType.PRIVATE);
final Fragment privateFragment =
privateFragmentConstructor.constructAndGetFragment();
privateFragment.setArguments(privateOnly);
fragments.add(privateFragment);
}
result = new Fragment[fragments.size()];
fragments.toArray(result);
} catch (Exception e) {
Log.e(TAG, "Failed to create fragment");
}
return result;
}
interface FragmentConstructor {
Fragment constructAndGetFragment();
}
interface PrivateSpaceInfoProvider {
default boolean isPrivateSpaceLocked(Context context) {
return PrivateSpaceMaintainer.getInstance(context).isPrivateSpaceLocked();
}
}
interface ManagedProfileInfoProvider {
default UserHandle getManagedProfile(Context context) {
return Utils.getManagedProfile(context.getSystemService(UserManager.class));
}
}
static class ViewPagerAdapter extends FragmentStateAdapter {
@@ -256,5 +384,22 @@ public abstract class ProfileSelectFragment extends DashboardFragment {
public int getItemCount() {
return mChildFragments.length;
}
private int getTabForPosition(int position) {
if (position >= mChildFragments.length) {
Log.e(TAG, "tab requested for out of bound position " + position);
return PERSONAL_TAB;
}
@ProfileType
int profileType = mChildFragments[position].getArguments().getInt(EXTRA_PROFILE);
if (profileType == ProfileType.WORK) {
return WORK_TAB;
}
if (profileType == ProfileType.PRIVATE) {
return PRIVATE_TAB;
}
return PERSONAL_TAB;
}
}
}

View File

@@ -16,8 +16,6 @@
package com.android.settings.dashboard.profileselector;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import com.android.settings.R;
@@ -39,19 +37,11 @@ public final class ProfileSelectKeyboardFragment extends ProfileSelectFragment {
@Override
public Fragment[] getFragments() {
final Bundle personalOnly = new Bundle();
personalOnly.putInt(EXTRA_PROFILE, ProfileType.PERSONAL);
final Fragment personalFragment = new AvailableVirtualKeyboardFragment();
personalFragment.setArguments(personalOnly);
final Bundle workOnly = new Bundle();
workOnly.putInt(EXTRA_PROFILE, ProfileType.WORK);
final Fragment workFragment = new AvailableVirtualKeyboardFragment();
workFragment.setArguments(workOnly);
return new Fragment[]{
personalFragment,
workFragment
};
return ProfileSelectFragment.getFragments(
getContext(),
null /* bundle */,
AvailableVirtualKeyboardFragment::new,
AvailableVirtualKeyboardFragment::new,
AvailableVirtualKeyboardFragment::new);
}
}

View File

@@ -45,20 +45,12 @@ public class ProfileSelectLocationFragment extends ProfileSelectFragment {
@Override
public Fragment[] getFragments() {
final Bundle workOnly = new Bundle();
workOnly.putInt(EXTRA_PROFILE, ProfileSelectFragment.ProfileType.WORK);
final Fragment workFragment = new LocationWorkProfileSettings();
workFragment.setArguments(workOnly);
final Bundle personalOnly = new Bundle();
personalOnly.putInt(EXTRA_PROFILE, ProfileSelectFragment.ProfileType.PERSONAL);
final Fragment personalFragment = new LocationPersonalSettings();
personalFragment.setArguments(personalOnly);
return new Fragment[]{
personalFragment,
workFragment
};
return ProfileSelectFragment.getFragments(
getContext(),
null /* bundle */,
LocationPersonalSettings::new,
LocationWorkProfileSettings::new,
LocationPersonalSettings::new);
}
@Override

View File

@@ -16,8 +16,6 @@
package com.android.settings.dashboard.profileselector;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import com.android.settings.R;
@@ -31,19 +29,12 @@ public class ProfileSelectLocationServicesFragment extends ProfileSelectFragment
@Override
public Fragment[] getFragments() {
final Bundle workOnly = new Bundle();
workOnly.putInt(EXTRA_PROFILE, ProfileType.WORK);
final Fragment workFragment = new LocationServicesForWork();
workFragment.setArguments(workOnly);
final Bundle personalOnly = new Bundle();
personalOnly.putInt(EXTRA_PROFILE, ProfileType.PERSONAL);
final Fragment personalFragment = new LocationServices();
personalFragment.setArguments(personalOnly);
return new Fragment[]{
personalFragment, // 0
workFragment
};
return ProfileSelectFragment.getFragments(
getContext(),
null /* bundle */,
LocationServices::new,
LocationServicesForWork::new,
LocationServices::new);
}
@Override

View File

@@ -31,19 +31,12 @@ public class ProfileSelectManageApplications extends ProfileSelectFragment {
@Override
public Fragment[] getFragments() {
final Bundle workOnly = getArguments() != null ? getArguments().deepCopy() : new Bundle();
workOnly.putInt(EXTRA_PROFILE, ProfileSelectFragment.ProfileType.WORK);
final Fragment workFragment = new ManageApplications();
workFragment.setArguments(workOnly);
final Bundle personalOnly = getArguments() != null ? getArguments() : new Bundle();
personalOnly.putInt(EXTRA_PROFILE, ProfileSelectFragment.ProfileType.PERSONAL);
final Fragment personalFragment = new ManageApplications();
personalFragment.setArguments(personalOnly);
return new Fragment[]{
personalFragment, //0
workFragment
};
return ProfileSelectFragment.getFragments(
getContext(),
getArguments(),
ManageApplications::new,
ManageApplications::new,
ManageApplications::new);
}
@Override

View File

@@ -51,22 +51,11 @@ public final class ProfileSelectPhysicalKeyboardFragment extends ProfileSelectFr
@Override
public Fragment[] getFragments() {
final Bundle personalOnly = new Bundle();
personalOnly.putInt(EXTRA_PROFILE, ProfileType.PERSONAL);
final Fragment personalFragment = new NewKeyboardLayoutEnabledLocalesFragment();
personalOnly.putParcelable(
Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, mInputDeviceIdentifier);
personalFragment.setArguments(personalOnly);
final Bundle workOnly = new Bundle();
workOnly.putInt(EXTRA_PROFILE, ProfileType.WORK);
final Fragment workFragment = new NewKeyboardLayoutEnabledLocalesFragment();
workOnly.putParcelable(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, mInputDeviceIdentifier);
workFragment.setArguments(workOnly);
return new Fragment[]{
personalFragment,
workFragment
};
return ProfileSelectFragment.getFragments(
getContext(),
null /* bundle */,
NewKeyboardLayoutEnabledLocalesFragment::new,
NewKeyboardLayoutEnabledLocalesFragment::new,
NewKeyboardLayoutEnabledLocalesFragment::new);
}
}

View File

@@ -193,20 +193,12 @@ public class ProfileSelectStorageFragment extends ProfileSelectFragment {
return mFragments;
}
final Bundle workBundle = new Bundle();
workBundle.putInt(EXTRA_PROFILE, ProfileType.WORK);
final Fragment workFragment = new StorageCategoryFragment();
workFragment.setArguments(workBundle);
final Bundle personalBundle = new Bundle();
personalBundle.putInt(EXTRA_PROFILE, ProfileType.PERSONAL);
final Fragment personalFragment = new StorageCategoryFragment();
personalFragment.setArguments(personalBundle);
mFragments = new Fragment[] {
personalFragment,
workFragment
};
mFragments = ProfileSelectFragment.getFragments(
getContext(),
null /* bundle */,
StorageCategoryFragment::new,
StorageCategoryFragment::new,
StorageCategoryFragment::new);
return mFragments;
}

View File

@@ -37,6 +37,7 @@ import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment.ProfileType;
import com.android.settings.deviceinfo.storage.ManageStoragePreferenceController;
import com.android.settings.deviceinfo.storage.NonCurrentUserController;
import com.android.settings.deviceinfo.storage.StorageAsyncLoader;
@@ -85,7 +86,7 @@ public class StorageCategoryFragment extends DashboardFragment
private StorageItemPreferenceController mPreferenceController;
private List<NonCurrentUserController> mNonCurrentUsers;
private boolean mIsWorkProfile;
private @ProfileType int mProfileType;
private int mUserId;
private boolean mIsLoadedFromCache;
private StorageCacheHelper mStorageCacheHelper;
@@ -163,9 +164,9 @@ public class StorageCategoryFragment extends DashboardFragment
// These member variables are initialized befoer super.onAttach for
// createPreferenceControllers to work correctly.
mUserManager = context.getSystemService(UserManager.class);
mIsWorkProfile = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE)
== ProfileSelectFragment.ProfileType.WORK;
mUserId = Utils.getCurrentUserId(mUserManager, mIsWorkProfile);
mProfileType = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE);
mUserId = Utils.getCurrentUserIdOfType(mUserManager, mProfileType);
mStorageCacheHelper = new StorageCacheHelper(getContext(), mUserId);
super.onAttach(context);
@@ -229,8 +230,12 @@ public class StorageCategoryFragment extends DashboardFragment
@Override
public int getMetricsCategory() {
return mIsWorkProfile ? SettingsEnums.SETTINGS_STORAGE_CATEGORY_WORK :
SettingsEnums.SETTINGS_STORAGE_CATEGORY;
if (mProfileType == ProfileSelectFragment.ProfileType.WORK) {
return SettingsEnums.SETTINGS_STORAGE_CATEGORY_WORK;
} else if (mProfileType == ProfileSelectFragment.ProfileType.PRIVATE) {
return SettingsEnums.SETTINGS_STORAGE_CATEGORY_PRIVATE;
}
return SettingsEnums.SETTINGS_STORAGE_CATEGORY;
}
@Override
@@ -248,11 +253,12 @@ public class StorageCategoryFragment extends DashboardFragment
final List<AbstractPreferenceController> controllers = new ArrayList<>();
final StorageManager sm = context.getSystemService(StorageManager.class);
mPreferenceController = new StorageItemPreferenceController(context, this,
null /* volume */, new StorageManagerVolumeProvider(sm), mIsWorkProfile);
null /* volume */, new StorageManagerVolumeProvider(sm), mProfileType);
controllers.add(mPreferenceController);
mNonCurrentUsers = mIsWorkProfile ? EMPTY_LIST :
NonCurrentUserController.getNonCurrentUserControllers(context, mUserManager);
mNonCurrentUsers = mProfileType == ProfileSelectFragment.ProfileType.PERSONAL
? NonCurrentUserController.getNonCurrentUserControllers(context, mUserManager)
: EMPTY_LIST;
controllers.addAll(mNonCurrentUsers);
return controllers;
}

View File

@@ -308,7 +308,6 @@ public class StorageDashboardFragment extends DashboardFragment
// These member variables are initialized befoer super.onAttach for
// createPreferenceControllers to work correctly.
mUserManager = context.getSystemService(UserManager.class);
mIsWorkProfile = false;
mUserId = UserHandle.myUserId();
mStorageCacheHelper = new StorageCacheHelper(getContext(), mUserId);
@@ -423,7 +422,7 @@ public class StorageDashboardFragment extends DashboardFragment
final List<AbstractPreferenceController> controllers = new ArrayList<>();
final StorageManager sm = context.getSystemService(StorageManager.class);
mPreferenceController = new StorageItemPreferenceController(context, this,
null /* volume */, new StorageManagerVolumeProvider(sm), mIsWorkProfile);
null /* volume */, new StorageManagerVolumeProvider(sm));
controllers.add(mPreferenceController);
mNonCurrentUsers = NonCurrentUserController.getNonCurrentUserControllers(context,
@@ -467,8 +466,7 @@ public class StorageDashboardFragment extends DashboardFragment
final UserManager userManager = context.getSystemService(UserManager.class);
final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new StorageItemPreferenceController(context, null /* host */,
null /* volume */, new StorageManagerVolumeProvider(sm),
false /* isWorkProfile */));
null /* volume */, new StorageManagerVolumeProvider(sm)));
controllers.addAll(NonCurrentUserController.getNonCurrentUserControllers(
context, userManager));
return controllers;

View File

@@ -27,6 +27,7 @@ import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment.ProfileType;
import com.android.settings.deviceinfo.storage.StorageCacheHelper;
import com.android.settingslib.deviceinfo.PrivateStorageInfo;
import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
@@ -62,8 +63,8 @@ public class TopLevelStoragePreferenceController extends BasePreferenceControlle
@VisibleForTesting
protected Future refreshSummaryThread(Preference preference) {
int userId = Utils.getCurrentUserId(mContext.getSystemService(UserManager.class),
/* isWorkProfile */ false);
int userId = Utils.getCurrentUserIdOfType(
mContext.getSystemService(UserManager.class), ProfileType.PERSONAL);
final StorageCacheHelper storageCacheHelper = new StorageCacheHelper(mContext, userId);
long cachedUsedSize = storageCacheHelper.retrieveUsedSize();
long cachedTotalSize = storageCacheHelper.retrieveCachedSize().totalSize;

View File

@@ -17,11 +17,13 @@
package com.android.settings.deviceinfo.storage;
import static com.android.settings.dashboard.profileselector.ProfileSelectFragment.PERSONAL_TAB;
import static com.android.settings.dashboard.profileselector.ProfileSelectFragment.PRIVATE_TAB;
import static com.android.settings.dashboard.profileselector.ProfileSelectFragment.WORK_TAB;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -47,6 +49,7 @@ import com.android.settings.Utils;
import com.android.settings.applications.manageapplications.ManageApplications;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
import com.android.settings.deviceinfo.StorageItemPreference;
import com.android.settings.deviceinfo.storage.StorageUtils.SystemInfoFragment;
import com.android.settings.overlay.FeatureFactory;
@@ -108,33 +111,33 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
private final Fragment mFragment;
private final MetricsFeatureProvider mMetricsFeatureProvider;
private final StorageVolumeProvider mSvp;
private VolumeInfo mVolume;
@Nullable private VolumeInfo mVolume;
private int mUserId;
private long mUsedBytes;
private long mTotalSize;
private List<StorageItemPreference> mPrivateStorageItemPreferences;
private PreferenceScreen mScreen;
@Nullable private List<StorageItemPreference> mPrivateStorageItemPreferences;
@Nullable private PreferenceScreen mScreen;
@VisibleForTesting
Preference mPublicStoragePreference;
@Nullable Preference mPublicStoragePreference;
@VisibleForTesting
StorageItemPreference mImagesPreference;
@Nullable StorageItemPreference mImagesPreference;
@VisibleForTesting
StorageItemPreference mVideosPreference;
@Nullable StorageItemPreference mVideosPreference;
@VisibleForTesting
StorageItemPreference mAudioPreference;
@Nullable StorageItemPreference mAudioPreference;
@VisibleForTesting
StorageItemPreference mAppsPreference;
@Nullable StorageItemPreference mAppsPreference;
@VisibleForTesting
StorageItemPreference mGamesPreference;
@Nullable StorageItemPreference mGamesPreference;
@VisibleForTesting
StorageItemPreference mDocumentsAndOtherPreference;
@Nullable StorageItemPreference mDocumentsAndOtherPreference;
@VisibleForTesting
StorageItemPreference mSystemPreference;
@Nullable StorageItemPreference mSystemPreference;
@VisibleForTesting
StorageItemPreference mTrashPreference;
@Nullable StorageItemPreference mTrashPreference;
private boolean mIsWorkProfile;
private final int mProfileType;
private StorageCacheHelper mStorageCacheHelper;
// The mIsDocumentsPrefShown being used here is to prevent a flicker problem from displaying
@@ -142,15 +145,24 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
private boolean mIsDocumentsPrefShown;
private boolean mIsPreferenceOrderedBySize;
public StorageItemPreferenceController(Context context, Fragment hostFragment,
VolumeInfo volume, StorageVolumeProvider svp, boolean isWorkProfile) {
public StorageItemPreferenceController(
Context context, Fragment hostFragment, VolumeInfo volume, StorageVolumeProvider svp) {
this(context, hostFragment, volume, svp, ProfileSelectFragment.ProfileType.PERSONAL);
}
public StorageItemPreferenceController(
Context context,
Fragment hostFragment,
@Nullable VolumeInfo volume,
StorageVolumeProvider svp,
@ProfileSelectFragment.ProfileType int profileType) {
super(context);
mPackageManager = context.getPackageManager();
mUserManager = context.getSystemService(UserManager.class);
mFragment = hostFragment;
mVolume = volume;
mSvp = svp;
mIsWorkProfile = isWorkProfile;
mProfileType = profileType;
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
mUserId = getCurrentUserId();
mIsDocumentsPrefShown = isDocumentsPrefShown();
@@ -168,7 +180,7 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
@VisibleForTesting
int getCurrentUserId() {
return Utils.getCurrentUserId(mUserManager, mIsWorkProfile);
return Utils.getCurrentUserIdOfType(mUserManager, mProfileType);
}
@Override
@@ -229,7 +241,9 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
mVolume = volume;
if (mPublicStoragePreference != null) {
mPublicStoragePreference.setVisible(isValidPublicVolume() && !mIsWorkProfile);
mPublicStoragePreference.setVisible(
isValidPublicVolume()
&& mProfileType == ProfileSelectFragment.ProfileType.PERSONAL);
}
// If isValidPrivateVolume() is true, these preferences will become visible at
@@ -327,9 +341,16 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
* Sets the user id for which this preference controller is handling.
*/
public void setUserId(UserHandle userHandle) {
if (mIsWorkProfile && !mUserManager.isManagedProfile(userHandle.getIdentifier())) {
if (mProfileType == ProfileSelectFragment.ProfileType.WORK
&& !mUserManager.isManagedProfile(userHandle.getIdentifier())) {
throw new IllegalArgumentException("Only accept work profile userHandle");
}
UserInfo userInfo = mUserManager.getUserInfo(userHandle.getIdentifier());
if (mProfileType == ProfileSelectFragment.ProfileType.PRIVATE
&& (userInfo == null || userInfo.isPrivateProfile())) {
throw new IllegalArgumentException("Only accept private profile userHandle");
}
mUserId = userHandle.getIdentifier();
tintPreference(mPublicStoragePreference);
@@ -498,8 +519,13 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
private Bundle getWorkAnnotatedBundle(int additionalCapacity) {
final Bundle args = new Bundle(1 + additionalCapacity);
args.putInt(SettingsActivity.EXTRA_SHOW_FRAGMENT_TAB,
mIsWorkProfile ? WORK_TAB : PERSONAL_TAB);
if (mProfileType == ProfileSelectFragment.ProfileType.WORK) {
args.putInt(SettingsActivity.EXTRA_SHOW_FRAGMENT_TAB, WORK_TAB);
} else if (mProfileType == ProfileSelectFragment.ProfileType.PRIVATE) {
args.putInt(SettingsActivity.EXTRA_SHOW_FRAGMENT_TAB, PRIVATE_TAB);
} else {
args.putInt(SettingsActivity.EXTRA_SHOW_FRAGMENT_TAB, PERSONAL_TAB);
}
return args;
}

View File

@@ -84,6 +84,16 @@ public class AvailableVirtualKeyboardFragment extends DashboardFragment
newUserAwareContext = context.createContextAsUser(UserHandle.of(newUserId), 0);
break;
}
case ProfileSelectFragment.ProfileType.PRIVATE: {
// If the user is a private profile user, use currentUserId directly. Or get the
// private profile userId instead.
newUserId = userManager.isPrivateProfile()
? currentUserId
: Utils.getCurrentUserIdOfType(
userManager, ProfileSelectFragment.ProfileType.PRIVATE);
newUserAwareContext = context.createContextAsUser(UserHandle.of(newUserId), 0);
break;
}
case ProfileSelectFragment.ProfileType.PERSONAL: {
// Use the parent user of the current user if the current user is profile.
final UserHandle currentUser = UserHandle.of(currentUserId);

View File

@@ -77,6 +77,15 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
? currentUserId : Utils.getManagedProfileId(userManager, currentUserId);
break;
}
case ProfileSelectFragment.ProfileType.PRIVATE: {
// If the user is a private profile user, use currentUserId directly. Or get the
// private profile userId instead.
newUserId = userManager.isPrivateProfile()
? currentUserId
: Utils.getCurrentUserIdOfType(
userManager, ProfileSelectFragment.ProfileType.PRIVATE);
break;
}
case ProfileSelectFragment.ProfileType.PERSONAL: {
final UserHandle primaryUser = userManager.getPrimaryUser().getUserHandle();
newUserId = primaryUser.getIdentifier();

View File

@@ -131,7 +131,17 @@ public class PrivateSpaceMaintainer {
return false;
}
static synchronized PrivateSpaceMaintainer getInstance(Context context) {
/** Returns true when the PS is locked or when PS doesn't exist, false otherwise. */
public synchronized boolean isPrivateSpaceLocked() {
if (!doesPrivateSpaceExist()) {
return true;
}
return mUserManager.isQuietModeEnabled(mUserHandle);
}
/** Returns the instance of {@link PrivateSpaceMaintainer} */
public static synchronized PrivateSpaceMaintainer getInstance(Context context) {
if (sPrivateSpaceMaintainer == null) {
sPrivateSpaceMaintainer = new PrivateSpaceMaintainer(context);
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2023 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.settings.users
import android.content.Context
import androidx.preference.PreferenceFragmentCompat
import com.android.settings.Utils
import com.android.settings.dashboard.profileselector.ProfileSelectFragment
class AutoSyncPrivateDataPreferenceController(
context: Context?, parent: PreferenceFragmentCompat?)
: AutoSyncDataPreferenceController(context, parent) {
init {
mUserHandle = Utils
.getProfileOfType(mUserManager, ProfileSelectFragment.ProfileType.PRIVATE)
}
override fun getPreferenceKey(): String {
return KEY_AUTO_SYNC_PRIVATE_ACCOUNT
}
override fun isAvailable(): Boolean {
return (mUserHandle != null
&& mUserManager.getUserInfo(mUserHandle.identifier).isPrivateProfile)
}
companion object {
private const val KEY_AUTO_SYNC_PRIVATE_ACCOUNT = "auto_sync_private_account_data"
}
}

View File

@@ -59,6 +59,7 @@ android_robolectric_test {
"androidx.test.rules",
"androidx.test.runner",
"flag-junit",
"flag-junit-base",
"aconfig_settings_flags_lib",
"platform-test-annotations",
"Settings-testutils2",

View File

@@ -19,6 +19,7 @@ package com.android.settings.dashboard.profileselector;
import static android.content.Intent.EXTRA_USER_ID;
import static com.android.settings.dashboard.profileselector.ProfileSelectFragment.PERSONAL_TAB;
import static com.android.settings.dashboard.profileselector.ProfileSelectFragment.PRIVATE_TAB;
import static com.android.settings.dashboard.profileselector.ProfileSelectFragment.WORK_TAB;
import static com.google.common.truth.Truth.assertThat;
@@ -29,6 +30,9 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Flags;
import android.os.UserHandle;
import android.platform.test.flag.junit.SetFlagsRule;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
@@ -38,6 +42,7 @@ import com.android.settings.SettingsPreferenceFragmentTest;
import com.android.settings.testutils.shadow.ShadowUserManager;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
@@ -60,6 +65,7 @@ public class ProfileSelectFragmentTest {
private TestProfileSelectFragment mFragment;
private FragmentActivity mActivity;
private ShadowUserManager mUserManager;
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@Before
public void setUp() {
@@ -85,6 +91,14 @@ public class ProfileSelectFragmentTest {
assertThat(mFragment.getTabId(mActivity, bundle)).isEqualTo(WORK_TAB);
}
@Test
public void getTabId_setArgumentPrivate_setCorrectTab() {
final Bundle bundle = new Bundle();
bundle.putInt(SettingsActivity.EXTRA_SHOW_FRAGMENT_TAB, PRIVATE_TAB);
assertThat(mFragment.getTabId(mActivity, bundle)).isEqualTo(PRIVATE_TAB);
}
@Test
public void getTabId_setArgumentPersonal_setCorrectTab() {
final Bundle bundle = new Bundle();
@@ -104,6 +118,16 @@ public class ProfileSelectFragmentTest {
assertThat(mFragment.getTabId(mActivity, bundle)).isEqualTo(WORK_TAB);
}
@Test
public void getTabId_setPrivateId_getCorrectTab() {
mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE);
final Bundle bundle = new Bundle();
bundle.putInt(EXTRA_USER_ID, 11);
mUserManager.setPrivateProfile(11, "private", 0);
assertThat(mFragment.getTabId(mActivity, bundle)).isEqualTo(PRIVATE_TAB);
}
@Test
public void getTabId_setPersonalId_getCorrectTab() {
final Bundle bundle = new Bundle();
@@ -124,12 +148,120 @@ public class ProfileSelectFragmentTest {
assertThat(mFragment.getTabId(mActivity, null)).isEqualTo(WORK_TAB);
}
@Test
public void testGetFragments_whenOnlyPersonal_returnsOneFragment() {
mSetFlagsRule.disableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE);
Fragment[] fragments = ProfileSelectFragment.getFragments(
mContext,
null /* bundle */,
TestProfileSelectFragment::new,
TestProfileSelectFragment::new,
TestProfileSelectFragment::new);
assertThat(fragments).hasLength(1);
}
@Test
public void testGetFragments_whenPrivateDisabled_returnsOneFragment() {
Fragment[] fragments = ProfileSelectFragment.getFragments(
mContext,
null /* bundle */,
TestProfileSelectFragment::new,
TestProfileSelectFragment::new,
TestProfileSelectFragment::new,
new ProfileSelectFragment.PrivateSpaceInfoProvider() {
@Override
public boolean isPrivateSpaceLocked(Context context) {
return true;
}
},
new ProfileSelectFragment.ManagedProfileInfoProvider() {
@Override
public UserHandle getManagedProfile(Context context) {
return null;
}
});
assertThat(fragments).hasLength(1);
}
@Test
public void testGetFragments_whenPrivateEnabled_returnsTwoFragments() {
mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE);
Fragment[] fragments = ProfileSelectFragment.getFragments(
mContext,
null /* bundle */,
TestProfileSelectFragment::new,
TestProfileSelectFragment::new,
TestProfileSelectFragment::new,
new ProfileSelectFragment.PrivateSpaceInfoProvider() {
@Override
public boolean isPrivateSpaceLocked(Context context) {
return false;
}
},
new ProfileSelectFragment.ManagedProfileInfoProvider() {
@Override
public UserHandle getManagedProfile(Context context) {
return null;
}
});
assertThat(fragments).hasLength(2);
}
@Test
public void testGetFragments_whenManagedProfile_returnsTwoFragments() {
mSetFlagsRule.disableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE);
Fragment[] fragments = ProfileSelectFragment.getFragments(
mContext,
null /* bundle */,
TestProfileSelectFragment::new,
TestProfileSelectFragment::new,
TestProfileSelectFragment::new,
new ProfileSelectFragment.PrivateSpaceInfoProvider() {
@Override
public boolean isPrivateSpaceLocked(Context context) {
return false;
}
},
new ProfileSelectFragment.ManagedProfileInfoProvider() {
@Override
public UserHandle getManagedProfile(Context context) {
return new UserHandle(123);
}
});
assertThat(fragments).hasLength(2);
}
@Test
public void testGetFragments_whenAllProfiles_returnsThreeFragments() {
mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE);
Fragment[] fragments = ProfileSelectFragment.getFragments(
mContext,
null /* bundle */,
TestProfileSelectFragment::new,
TestProfileSelectFragment::new,
TestProfileSelectFragment::new,
new ProfileSelectFragment.PrivateSpaceInfoProvider() {
@Override
public boolean isPrivateSpaceLocked(Context context) {
return false;
}
},
new ProfileSelectFragment.ManagedProfileInfoProvider() {
@Override
public UserHandle getManagedProfile(Context context) {
return new UserHandle(123);
}
});
assertThat(fragments).hasLength(3);
}
public static class TestProfileSelectFragment extends ProfileSelectFragment {
@Override
public Fragment[] getFragments() {
return new Fragment[]{
new SettingsPreferenceFragmentTest.TestFragment(), //0
new SettingsPreferenceFragmentTest.TestFragment(),
new SettingsPreferenceFragmentTest.TestFragment()
};
}

View File

@@ -39,10 +39,12 @@ public class ProfileSelectLocationFragmentTest {
@Test
public void getFragments_containsCorrectBundle() {
assertThat(mProfileSelectLocationFragment.getFragments().length).isEqualTo(2);
assertThat(mProfileSelectLocationFragment.getFragments().length).isEqualTo(3);
assertThat(mProfileSelectLocationFragment.getFragments()[0].getArguments().getInt(
EXTRA_PROFILE, -1)).isEqualTo(ProfileSelectFragment.ProfileType.PERSONAL);
assertThat(mProfileSelectLocationFragment.getFragments()[1].getArguments().getInt(
EXTRA_PROFILE, -1)).isEqualTo(ProfileSelectFragment.ProfileType.WORK);
assertThat(mProfileSelectLocationFragment.getFragments()[1].getArguments().getInt(
EXTRA_PROFILE, -1)).isEqualTo(ProfileSelectFragment.ProfileType.PRIVATE);
}
}

View File

@@ -52,6 +52,7 @@ import com.android.settings.SettingsActivity;
import com.android.settings.SubSettings;
import com.android.settings.applications.manageapplications.ManageApplications;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment.ProfileType;
import com.android.settings.deviceinfo.StorageItemPreference;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settingslib.deviceinfo.StorageVolumeProvider;
@@ -99,7 +100,7 @@ public class StorageItemPreferenceControllerTest {
// Note: null is passed as the Lifecycle because we are handling it outside of the normal
// Settings fragment lifecycle for test purposes.
mController = new StorageItemPreferenceController(mContext, mFragment, mVolume, mSvp,
false /* isWorkProfile */);
ProfileSelectFragment.ProfileType.PERSONAL);
mPreference = new StorageItemPreference(mContext);
// Inflate the preference and the widget.
@@ -175,7 +176,7 @@ public class StorageItemPreferenceControllerTest {
mPreference.setKey(StorageItemPreferenceController.IMAGES_KEY);
final Context mockContext = getMockContext();
mController = new StorageItemPreferenceController(mockContext, mFragment, mVolume,
mSvp, false /* isWorkProfile */);
mSvp, ProfileSelectFragment.ProfileType.PERSONAL);
mController.handlePreferenceTreeClick(mPreference);
final ArgumentCaptor<Intent> argumentCaptor = ArgumentCaptor.forClass(Intent.class);
@@ -192,7 +193,7 @@ public class StorageItemPreferenceControllerTest {
mPreference.setKey(StorageItemPreferenceController.AUDIO_KEY);
final Context mockContext = getMockContext();
mController = new StorageItemPreferenceController(mockContext, mFragment, mVolume,
mSvp, false /* isWorkProfile */);
mSvp, ProfileSelectFragment.ProfileType.PERSONAL);
mController.handlePreferenceTreeClick(mPreference);
final ArgumentCaptor<Intent> argumentCaptor = ArgumentCaptor.forClass(Intent.class);
@@ -242,7 +243,7 @@ public class StorageItemPreferenceControllerTest {
@Test
public void launchAppsIntent_forWork_settingsIntent() {
mController = new FakeStorageItemPreferenceController(mContext, mFragment, mVolume, mSvp,
true /* isWorkProfile */);
ProfileType.WORK);
mPreference.setKey(StorageItemPreferenceController.APPS_KEY);
mController.handlePreferenceTreeClick(mPreference);
@@ -272,7 +273,7 @@ public class StorageItemPreferenceControllerTest {
mPreference.setKey(StorageItemPreferenceController.DOCUMENTS_AND_OTHER_KEY);
final Context mockContext = getMockContext();
mController = new StorageItemPreferenceController(mockContext, mFragment, mVolume,
mSvp, false /* isWorkProfile */);
mSvp, ProfileSelectFragment.ProfileType.PERSONAL);
mController.handlePreferenceTreeClick(mPreference);
final ArgumentCaptor<Intent> argumentCaptor = ArgumentCaptor.forClass(Intent.class);
@@ -307,7 +308,7 @@ public class StorageItemPreferenceControllerTest {
mPreference.setKey(StorageItemPreferenceController.VIDEOS_KEY);
final Context mockContext = getMockContext();
mController = new StorageItemPreferenceController(mockContext, mFragment, mVolume,
mSvp, false /* isWorkProfile */);
mSvp, ProfileSelectFragment.ProfileType.PERSONAL);
mController.handlePreferenceTreeClick(mPreference);
final ArgumentCaptor<Intent> argumentCaptor = ArgumentCaptor.forClass(Intent.class);
@@ -457,8 +458,8 @@ public class StorageItemPreferenceControllerTest {
private static final int CURRENT_USER_ID = 10;
FakeStorageItemPreferenceController(Context context, Fragment hostFragment,
VolumeInfo volume, StorageVolumeProvider svp, boolean isWorkProfile) {
super(context, hostFragment, volume, svp, isWorkProfile);
VolumeInfo volume, StorageVolumeProvider svp, @ProfileType int profileType) {
super(context, hostFragment, volume, svp, profileType);
}
@Override

View File

@@ -17,6 +17,7 @@
package com.android.settings.testutils.shadow;
import static android.os.Build.VERSION_CODES.LOLLIPOP;
import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE;
import android.annotation.UserIdInt;
import android.content.pm.UserInfo;
@@ -223,6 +224,10 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager
mManagedProfiles.addAll(profileIds);
}
public void setPrivateProfile(int id, String name, int flags) {
mUserProfileInfos.add(new UserInfo(id, name, null, flags, USER_TYPE_PROFILE_PRIVATE));
}
public void setUserSwitcherEnabled(boolean userSwitchEnabled) {
mUserSwitchEnabled = userSwitchEnabled;
}