UX changes for the new cross profile settings page
Bug: 136249261 Bug: 140728653 Bug: 148594054 Test: make RunSettingsRoboTests ROBOTEST_FILTER=InteractAcrossProfilesControllerTest Test: make RunSettingsRoboTests ROBOTEST_FILTER=InteractAcrossProfilesDetailsTest Test: make RunSettingsRoboTests ROBOTEST_FILTER=InteractAcrossProfilesPreferenceControllerTest Test: make RunSettingsRoboTests ROBOTEST_FILTER=InteractAcrossProfilesSettingsTest Change-Id: I9666b34a03e5c082eed7c4120e70a07017ab7ef0
This commit is contained in:
@@ -17,10 +17,13 @@
|
||||
package com.android.settings.applications.specialaccess.interactacrossprofiles;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.CrossProfileApps;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
import java.util.List;
|
||||
@@ -33,12 +36,16 @@ public class InteractAcrossProfilesController extends BasePreferenceController {
|
||||
|
||||
private final Context mContext;
|
||||
private final UserManager mUserManager;
|
||||
private final PackageManager mPackageManager;
|
||||
private final CrossProfileApps mCrossProfileApps;
|
||||
|
||||
public InteractAcrossProfilesController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
|
||||
mContext = context;
|
||||
mUserManager = mContext.getSystemService(UserManager.class);
|
||||
mCrossProfileApps = mContext.getSystemService(CrossProfileApps.class);
|
||||
mPackageManager = mContext.getPackageManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,4 +58,17 @@ public class InteractAcrossProfilesController extends BasePreferenceController {
|
||||
}
|
||||
return DISABLED_FOR_USER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
final int connectedApps = InteractAcrossProfilesSettings.getNumberOfEnabledApps(
|
||||
mContext, mPackageManager, mUserManager, mCrossProfileApps);
|
||||
return connectedApps == 0
|
||||
? mContext.getResources().getString(
|
||||
R.string.interact_across_profiles_number_of_connected_apps_none)
|
||||
: mContext.getResources().getQuantityString(
|
||||
R.plurals.interact_across_profiles_number_of_connected_apps,
|
||||
connectedApps,
|
||||
connectedApps);
|
||||
}
|
||||
}
|
||||
|
@@ -22,13 +22,15 @@ import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.PermissionChecker;
|
||||
import android.content.pm.CrossProfileApps;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.util.IconDrawableFactory;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
@@ -51,6 +53,7 @@ public class InteractAcrossProfilesDetails extends AppInfoBase
|
||||
private UserManager mUserManager;
|
||||
private SwitchPreference mSwitchPref;
|
||||
private LayoutPreference mHeader;
|
||||
private PackageManager mPackageManager;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
@@ -59,6 +62,7 @@ public class InteractAcrossProfilesDetails extends AppInfoBase
|
||||
mContext = getContext();
|
||||
mCrossProfileApps = mContext.getSystemService(CrossProfileApps.class);
|
||||
mUserManager = mContext.getSystemService(UserManager.class);
|
||||
mPackageManager = mContext.getPackageManager();
|
||||
|
||||
addPreferencesFromResource(R.xml.interact_across_profiles_permissions_details);
|
||||
mSwitchPref = findPreference(INTERACT_ACROSS_PROFILES_SETTINGS_SWITCH);
|
||||
@@ -72,10 +76,17 @@ public class InteractAcrossProfilesDetails extends AppInfoBase
|
||||
}
|
||||
final UserHandle workProfile = getWorkProfile();
|
||||
final UserHandle personalProfile = mUserManager.getProfileParent(workProfile);
|
||||
addAppIcons(personalProfile, workProfile);
|
||||
addAppTitleAndIcons(personalProfile, workProfile);
|
||||
}
|
||||
|
||||
private void addAppIcons(UserHandle personalProfile, UserHandle workProfile) {
|
||||
private void addAppTitleAndIcons(UserHandle personalProfile, UserHandle workProfile) {
|
||||
final TextView title = mHeader.findViewById(R.id.entity_header_title);
|
||||
if (title != null) {
|
||||
final String appLabel = mPackageInfo.applicationInfo.loadLabel(
|
||||
mPackageManager).toString();
|
||||
title.setText(appLabel);
|
||||
}
|
||||
|
||||
final ImageView personalIconView = mHeader.findViewById(R.id.entity_header_icon_personal);
|
||||
if (personalIconView != null) {
|
||||
personalIconView.setImageDrawable(IconDrawableFactory.newInstance(mContext)
|
||||
@@ -114,35 +125,57 @@ public class InteractAcrossProfilesDetails extends AppInfoBase
|
||||
return true;
|
||||
}
|
||||
if (!isInteractAcrossProfilesEnabled()) {
|
||||
// TODO(b/148594054): Create a proper dialogue.
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setTitle(R.string.interact_across_profiles_consent_dialog_title)
|
||||
.setMessage(R.string.interact_across_profiles_consent_dialog_summary)
|
||||
.setPositiveButton(R.string.allow, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
enableInteractAcrossProfiles(true);
|
||||
refreshUi();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.deny, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
refreshUi();
|
||||
}
|
||||
})
|
||||
.create().show();
|
||||
} else {
|
||||
enableInteractAcrossProfiles(false);
|
||||
refreshUi();
|
||||
showConsentDialog();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void showConsentDialog() {
|
||||
final String appLabel = mPackageInfo.applicationInfo.loadLabel(mPackageManager).toString();
|
||||
|
||||
final View dialogView = getLayoutInflater().inflate(
|
||||
R.layout.interact_across_profiles_consent_dialog, null);
|
||||
|
||||
final TextView dialogTitle = dialogView.findViewById(
|
||||
R.id.interact_across_profiles_consent_dialog_title);
|
||||
dialogTitle.setText(
|
||||
getString(R.string.interact_across_profiles_consent_dialog_title, appLabel));
|
||||
|
||||
final TextView dialogSummary = dialogView.findViewById(
|
||||
R.id.interact_across_profiles_consent_dialog_summary);
|
||||
dialogSummary.setText(
|
||||
getString(R.string.interact_across_profiles_consent_dialog_summary, appLabel));
|
||||
|
||||
final TextView appDataSummary = dialogView.findViewById(R.id.app_data_summary);
|
||||
appDataSummary.setText(getString(
|
||||
R.string.interact_across_profiles_consent_dialog_app_data_summary, appLabel));
|
||||
|
||||
final TextView permissionsSummary = dialogView.findViewById(R.id.permissions_summary);
|
||||
permissionsSummary.setText(getString(
|
||||
R.string.interact_across_profiles_consent_dialog_permissions_summary, appLabel));
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setView(dialogView)
|
||||
.setPositiveButton(R.string.allow, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
enableInteractAcrossProfiles(true);
|
||||
refreshUi();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.deny, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
refreshUi();
|
||||
}
|
||||
})
|
||||
.create().show();
|
||||
}
|
||||
|
||||
private boolean isInteractAcrossProfilesEnabled() {
|
||||
return isInteractAcrossProfilesEnabled(
|
||||
mContext, mPackageName, mPackageInfo.applicationInfo.uid);
|
||||
}
|
||||
|
||||
private static boolean isInteractAcrossProfilesEnabled(Context context, String packageName, int uid) {
|
||||
static boolean isInteractAcrossProfilesEnabled(Context context, String packageName, int uid) {
|
||||
return PermissionChecker.PERMISSION_GRANTED
|
||||
== PermissionChecker.checkPermissionForPreflight(
|
||||
context,
|
||||
@@ -178,13 +211,21 @@ public class InteractAcrossProfilesDetails extends AppInfoBase
|
||||
return false;
|
||||
}
|
||||
|
||||
mSwitchPref.setChecked(isInteractAcrossProfilesEnabled());
|
||||
final ImageView horizontalArrowIcon = mHeader.findViewById(R.id.entity_header_swap_horiz);
|
||||
if (horizontalArrowIcon != null) {
|
||||
final Drawable icon = mSwitchPref.isChecked()
|
||||
? mContext.getDrawable(R.drawable.ic_swap_horiz_blue)
|
||||
: mContext.getDrawable(R.drawable.ic_swap_horiz_grey);
|
||||
horizontalArrowIcon.setImageDrawable(icon);
|
||||
if (isInteractAcrossProfilesEnabled()) {
|
||||
mSwitchPref.setChecked(true);
|
||||
mSwitchPref.setTitle(R.string.interact_across_profiles_switch_enabled);
|
||||
if (horizontalArrowIcon != null) {
|
||||
horizontalArrowIcon.setImageDrawable(
|
||||
mContext.getDrawable(R.drawable.ic_swap_horiz_blue));
|
||||
}
|
||||
} else {
|
||||
mSwitchPref.setChecked(false);
|
||||
mSwitchPref.setTitle(R.string.interact_across_profiles_switch_disabled);
|
||||
if (horizontalArrowIcon != null) {
|
||||
horizontalArrowIcon.setImageDrawable(
|
||||
mContext.getDrawable(R.drawable.ic_swap_horiz_grey));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@@ -73,7 +73,7 @@ public class InteractAcrossProfilesSettings extends EmptyTextSettings {
|
||||
screen.removeAll();
|
||||
|
||||
final ArrayList<Pair<ApplicationInfo, UserHandle>> crossProfileApps =
|
||||
collectConfigurableApps();
|
||||
collectConfigurableApps(mPackageManager, mUserManager, mCrossProfileApps);
|
||||
|
||||
final Context prefContext = getPrefContext();
|
||||
for (final Pair<ApplicationInfo, UserHandle> appData : crossProfileApps) {
|
||||
@@ -124,21 +124,37 @@ public class InteractAcrossProfilesSettings extends EmptyTextSettings {
|
||||
* @return the list of applications for the personal profile in the calling user's profile group
|
||||
* that can configure interact across profiles.
|
||||
*/
|
||||
ArrayList<Pair<ApplicationInfo, UserHandle>> collectConfigurableApps() {
|
||||
final UserHandle personalProfile = getPersonalProfileForCallingUser();
|
||||
static ArrayList<Pair<ApplicationInfo, UserHandle>> collectConfigurableApps(
|
||||
PackageManager packageManager, UserManager userManager,
|
||||
CrossProfileApps crossProfileApps) {
|
||||
final UserHandle personalProfile = getPersonalProfileForCallingUser(userManager);
|
||||
if (personalProfile == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
final ArrayList<Pair<ApplicationInfo, UserHandle>> crossProfileApps = new ArrayList<>();
|
||||
final List<PackageInfo> installedPackages = mPackageManager.getInstalledPackagesAsUser(
|
||||
final ArrayList<Pair<ApplicationInfo, UserHandle>> apps = new ArrayList<>();
|
||||
final List<PackageInfo> installedPackages = packageManager.getInstalledPackagesAsUser(
|
||||
GET_ACTIVITIES, personalProfile.getIdentifier());
|
||||
for (PackageInfo packageInfo : installedPackages) {
|
||||
if (mCrossProfileApps.canConfigureInteractAcrossProfiles(packageInfo.packageName)) {
|
||||
crossProfileApps.add(new Pair<>(packageInfo.applicationInfo, personalProfile));
|
||||
if (crossProfileApps.canConfigureInteractAcrossProfiles(packageInfo.packageName)) {
|
||||
apps.add(new Pair<>(packageInfo.applicationInfo, personalProfile));
|
||||
}
|
||||
}
|
||||
return crossProfileApps;
|
||||
return apps;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of applications that can interact across profiles.
|
||||
*/
|
||||
static int getNumberOfEnabledApps(
|
||||
Context context, PackageManager packageManager, UserManager userManager,
|
||||
CrossProfileApps crossProfileApps) {
|
||||
final ArrayList<Pair<ApplicationInfo, UserHandle>> apps =
|
||||
collectConfigurableApps(packageManager, userManager, crossProfileApps);
|
||||
apps.removeIf(
|
||||
app -> !InteractAcrossProfilesDetails.isInteractAcrossProfilesEnabled(
|
||||
context, app.first.packageName, app.first.uid));
|
||||
return apps.size();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,12 +162,12 @@ public class InteractAcrossProfilesSettings extends EmptyTextSettings {
|
||||
* Returns null if user is not in a profile group.
|
||||
*/
|
||||
@Nullable
|
||||
private UserHandle getPersonalProfileForCallingUser() {
|
||||
private static UserHandle getPersonalProfileForCallingUser(UserManager userManager) {
|
||||
final int callingUser = UserHandle.myUserId();
|
||||
if (mUserManager.getProfiles(callingUser).isEmpty()) {
|
||||
if (userManager.getProfiles(callingUser).isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final UserInfo parentProfile = mUserManager.getProfileParent(callingUser);
|
||||
final UserInfo parentProfile = userManager.getProfileParent(callingUser);
|
||||
return parentProfile == null
|
||||
? UserHandle.of(callingUser) : parentProfile.getUserHandle();
|
||||
}
|
||||
|
Reference in New Issue
Block a user