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:
kholoud mohamed
2020-02-05 11:14:11 +00:00
parent d4e2f78d9a
commit 00c46041b6
11 changed files with 407 additions and 78 deletions

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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();
}