Merge "Credential Manager Settings Improvement Bug fixes" into main

This commit is contained in:
Joy Babafemi
2025-01-21 11:12:25 -08:00
committed by Android (Google) Code Review
16 changed files with 136 additions and 67 deletions

View File

@@ -21,6 +21,7 @@ import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.content.pm.UserInfo;
import android.credentials.CredentialManager;
import android.os.UserHandle;
@@ -89,7 +90,8 @@ public class AccountDashboardFragment extends DashboardFragment {
forceUpdatePreferences();
}
};
cmpp.init(this, getFragmentManager(), getIntent(), delegate, /*isWorkProfile=*/false);
cmpp.init(this, getFragmentManager(), getIntent(), delegate,
/*isWorkProfile=*/false, /*isPrivateSpace=*/ false);
} else {
getSettingsLifecycle().addObserver(use(PasswordsPreferenceController.class));
}
@@ -98,7 +100,8 @@ public class AccountDashboardFragment extends DashboardFragment {
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
buildAutofillPreferenceControllers(context, controllers);
buildAutofillPreferenceControllers(context, controllers,
/*isWorkProfile=*/false, /*isPrivateSpace=*/ false);
final String[] authorities = getIntent().getStringArrayExtra(EXTRA_AUTHORITIES);
buildAccountPreferenceControllers(context, this /* parent */, authorities, controllers);
return controllers;
@@ -110,9 +113,13 @@ public class AccountDashboardFragment extends DashboardFragment {
}
static void buildAutofillPreferenceControllers(
Context context, List<AbstractPreferenceController> controllers) {
Context context,
List<AbstractPreferenceController> controllers,
boolean isWorkProfile,
boolean isPrivateSpace) {
if (CredentialManager.isServiceEnabled(context)) {
controllers.add(new DefaultCombinedPreferenceController(context));
controllers.add(new DefaultCombinedPreferenceController(
context, isWorkProfile, isPrivateSpace));
controllers.add(new DefaultWorkCombinedPreferenceController(context));
controllers.add(new DefaultPrivateCombinedPreferenceController(context));
} else {
@@ -162,7 +169,7 @@ public class AccountDashboardFragment extends DashboardFragment {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
buildAccountPreferenceControllers(
context, null /* parent */, null /* authorities*/, controllers);
buildAutofillPreferenceControllers(context, controllers);
buildAutofillPreferenceControllers(context, controllers, false, false);
return controllers;
}

View File

@@ -78,7 +78,8 @@ public class AccountPersonalDashboardFragment extends DashboardFragment {
forceUpdatePreferences();
}
};
cmpp.init(this, getFragmentManager(), getIntent(), delegate, /*isWorkProfile=*/false);
cmpp.init(this, getFragmentManager(),
getIntent(), delegate, /*isWorkProfile=*/false, /*isPrivateSpace=*/ false);
} else {
getSettingsLifecycle().addObserver(use(PasswordsPreferenceController.class));
}
@@ -87,7 +88,8 @@ public class AccountPersonalDashboardFragment extends DashboardFragment {
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
buildAutofillPreferenceControllers(context, controllers);
buildAutofillPreferenceControllers(
context, controllers, /*isWorkProfile=*/ false, /*isPrivateSpace=*/ false);
final String[] authorities = getIntent().getStringArrayExtra(EXTRA_AUTHORITIES);
buildAccountPreferenceControllers(context, this /* parent */, authorities, controllers);
return controllers;

View File

@@ -194,9 +194,6 @@ public class AccountPreferenceController extends AbstractPreferenceController
@Override
public void updateDynamicRawDataToIndex(List<SearchIndexableRaw> rawData) {
if (!isAvailable()) {
return;
}
final Resources res = mContext.getResources();
final String screenTitle = res.getString(R.string.account_settings_title);
@@ -288,12 +285,6 @@ public class AccountPreferenceController extends AbstractPreferenceController
}
private void updateUi() {
if (!isAvailable()) {
// This should not happen
Log.e(TAG, "We should not be showing settings for a managed profile");
return;
}
for (int i = 0, size = mProfiles.size(); i < size; i++) {
mProfiles.valueAt(i).pendingRemoval = true;
}

View File

@@ -77,7 +77,8 @@ public class AccountPrivateDashboardFragment extends DashboardFragment {
forceUpdatePreferences();
}
};
cmpp.init(this, getFragmentManager(), getIntent(), delegate, /*isWorkProfile=*/false);
cmpp.init(this, getFragmentManager(), getIntent(),
delegate, /*isWorkProfile=*/false, /*isPrivateSpace=*/true);
} else {
getSettingsLifecycle().addObserver(use(PasswordsPreferenceController.class));
}
@@ -86,7 +87,8 @@ public class AccountPrivateDashboardFragment extends DashboardFragment {
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
buildAutofillPreferenceControllers(context, controllers);
buildAutofillPreferenceControllers(
context, controllers, /*isWorkProfile=*/ false, /*isPrivateSpace=*/ true);
final String[] authorities = getIntent().getStringArrayExtra(EXTRA_AUTHORITIES);
buildAccountPreferenceControllers(context, authorities, controllers);
return controllers;

View File

@@ -78,7 +78,8 @@ public class AccountWorkProfileDashboardFragment extends DashboardFragment {
forceUpdatePreferences();
}
};
cmpp.init(this, getFragmentManager(), getIntent(), delegate, /*isWorkProfile=*/true);
cmpp.init(this, getFragmentManager(), getIntent(),
delegate, /*isWorkProfile=*/true, /*isPrivateSpace=*/false);
} else {
getSettingsLifecycle().addObserver(use(PasswordsPreferenceController.class));
}
@@ -87,7 +88,8 @@ public class AccountWorkProfileDashboardFragment extends DashboardFragment {
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
buildAutofillPreferenceControllers(context, controllers);
buildAutofillPreferenceControllers(
context, controllers, /*isWorkProfile=*/ true, /*isPrivateSpace=*/ false);
final String[] authorities = getIntent().getStringArrayExtra(EXTRA_AUTHORITIES);
buildAccountPreferenceControllers(context, this /* parent */, authorities, controllers);
return controllers;

View File

@@ -119,6 +119,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
private Optional<Boolean> mSimulateHiddenForTests = Optional.empty();
private boolean mIsWorkProfile = false;
private boolean mIsPrivateSpace = false;
private boolean mSimulateConnectedForTests = false;
public CredentialManagerPreferenceController(Context context, String preferenceKey) {
@@ -203,10 +204,12 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
FragmentManager fragmentManager,
@Nullable Intent launchIntent,
@NonNull Delegate delegate,
boolean isWorkProfile) {
boolean isWorkProfile,
boolean isPrivateSpace) {
fragment.getSettingsLifecycle().addObserver(this);
mFragmentManager = fragmentManager;
mIsWorkProfile = isWorkProfile;
mIsPrivateSpace = isPrivateSpace;
setDelegate(delegate);
verifyReceivedIntent(launchIntent);
@@ -496,7 +499,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
final Preference preference = new Preference(context);
preference.setOnPreferenceClickListener(
p -> {
context.startActivityAsUser(addNewServiceIntent, UserHandle.of(getUser()));
context.startActivityAsUser(addNewServiceIntent,
UserHandle.of(getUser()));
return true;
});
preference.setTitle(R.string.print_menu_item_add_service);
@@ -886,18 +890,12 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
}
protected int getUser() {
if (mIsWorkProfile) {
UserHandle workProfile = getWorkProfileUserHandle();
if (workProfile != null) {
return workProfile.getIdentifier();
}
}
return UserHandle.myUserId();
return UserUtils.getUser(mIsWorkProfile, mIsPrivateSpace, mContext);
}
private @Nullable UserHandle getWorkProfileUserHandle() {
if (mIsWorkProfile) {
return Utils.getManagedProfile(UserManager.get(mContext));
return UserUtils.getManagedProfile(UserManager.get(mContext));
}
return null;

View File

@@ -33,11 +33,12 @@ import com.android.settings.SettingsActivity;
*/
public class CredentialsPickerActivity extends SettingsActivity {
private static final String TAG = "CredentialsPickerActivity";
private boolean mIsWorkProfile;
private boolean mIsPrivateSpace;
/** Injects the fragment name into the intent so the correct fragment is opened. */
@VisibleForTesting
public static void injectFragmentIntoIntent(Context context, Intent intent) {
final int userId = UserHandle.myUserId();
public static void injectFragmentIntoIntent(Context context, Intent intent, int userId) {
final UserManager userManager = UserManager.get(context);
if (DefaultCombinedPickerWork.isUserHandledByFragment(userManager, userId)) {
@@ -57,8 +58,12 @@ public class CredentialsPickerActivity extends SettingsActivity {
final String packageName = getCallingPackage();
final Intent intent = getIntent();
mIsWorkProfile = intent.getBooleanExtra(UserUtils.EXTRA_IS_WORK_PROFILE, false);
mIsPrivateSpace = intent.getBooleanExtra(UserUtils.EXTRA_IS_PRIVATE_SPACE, false);
intent.putExtra(DefaultCombinedPicker.EXTRA_PACKAGE_NAME, packageName);
injectFragmentIntoIntent(this, intent);
injectFragmentIntoIntent(this, intent, UserUtils.getUser(
mIsWorkProfile, mIsPrivateSpace, this));
super.onCreate(savedInstanceState);
}

View File

@@ -61,6 +61,8 @@ import java.util.List;
public class DefaultCombinedPicker extends DefaultAppPickerFragment {
private boolean mIsWorkProfile;
private boolean mIsPrivateSpace;
private static final String TAG = "DefaultCombinedPicker";
public static final String AUTOFILL_SETTING = Settings.Secure.AUTOFILL_SERVICE;
@@ -82,6 +84,10 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
super.onCreate(savedInstanceState);
final Activity activity = getActivity();
mIsWorkProfile = activity.getIntent().getBooleanExtra(
UserUtils.EXTRA_IS_WORK_PROFILE, false);
mIsPrivateSpace = activity.getIntent().getBooleanExtra(
UserUtils.EXTRA_IS_PRIVATE_SPACE, false);
if (activity != null && activity.getIntent().getStringExtra(EXTRA_PACKAGE_NAME) != null) {
mCancelListener =
(d, w) -> {
@@ -520,9 +526,6 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
}
protected int getUser() {
if (mIntentSenderUserId >= 0) {
return mIntentSenderUserId;
}
return UserHandle.myUserId();
return UserUtils.getUser(mIsWorkProfile, mIsPrivateSpace, getContext());
}
}

View File

@@ -21,11 +21,6 @@ import android.os.UserManager;
public class DefaultCombinedPickerPrivate extends DefaultCombinedPicker {
@Override
protected int getUser() {
return UserHandle.myUserId();
}
/** Returns whether the user is handled by this fragment. */
public static boolean isUserHandledByFragment(UserManager userManager) {
return android.os.Flags.allowPrivateProfile()

View File

@@ -22,11 +22,6 @@ import android.os.UserManager;
public class DefaultCombinedPickerWork extends DefaultCombinedPicker {
private static final String TAG = "DefaultCombinedPickerWork";
@Override
protected int getUser() {
return UserHandle.myUserId();
}
/** Returns whether the user is handled by this fragment. */
public static boolean isUserHandledByFragment(UserManager userManager, int userId) {
return userManager.isManagedProfile(userId);

View File

@@ -48,7 +48,8 @@ import java.util.List;
import java.util.concurrent.Executor;
public class DefaultCombinedPreferenceController extends DefaultAppPreferenceController {
private final boolean mIsWorkProfile;
private final boolean mIsPrivateSpace;
private static final Intent AUTOFILL_PROBE = new Intent(AutofillService.SERVICE_INTERFACE);
private static final String TAG = "DefaultCombinedPreferenceController";
@@ -56,11 +57,14 @@ public class DefaultCombinedPreferenceController extends DefaultAppPreferenceCon
private final CredentialManager mCredentialManager;
private final Executor mExecutor;
public DefaultCombinedPreferenceController(Context context) {
public DefaultCombinedPreferenceController(Context context,
boolean isWorkProfile, boolean isPrivateSpace) {
super(context);
mExecutor = ContextCompat.getMainExecutor(context);
mAutofillManager = mContext.getSystemService(AutofillManager.class);
mIsWorkProfile = isWorkProfile;
mIsPrivateSpace = isPrivateSpace;
if (CredentialManager.isServiceEnabled(context)) {
mCredentialManager = mContext.getSystemService(CredentialManager.class);
@@ -209,14 +213,17 @@ public class DefaultCombinedPreferenceController extends DefaultAppPreferenceCon
}
protected int getUser() {
return UserHandle.myUserId();
return UserUtils.getUser(mIsWorkProfile, mIsPrivateSpace, mContext);
}
/** Creates an intent to open the credential picker. */
private Intent createIntentToOpenPicker() {
final Context context =
mContext.createContextAsUser(UserHandle.of(getUser()), /* flags= */ 0);
return new Intent(context, CredentialsPickerActivity.class);
Intent intent = new Intent(context, CredentialsPickerActivity.class);
intent.putExtra(UserUtils.EXTRA_IS_WORK_PROFILE, mIsWorkProfile);
intent.putExtra(UserUtils.EXTRA_IS_PRIVATE_SPACE, mIsPrivateSpace);
return intent;
}
private void removePrimaryProvider() {

View File

@@ -22,7 +22,7 @@ import com.android.settings.Utils
import com.android.settings.dashboard.profileselector.ProfileSelectFragment
import com.android.settingslib.applications.DefaultAppInfo
class DefaultPrivateCombinedPreferenceController(context: Context?) : DefaultCombinedPreferenceController(context) {
class DefaultPrivateCombinedPreferenceController(context: Context?) : DefaultCombinedPreferenceController(context, /*isWorkProfile=*/ false, /*isPrivateSpace=*/ true) {
private val userHandle: UserHandle? =
Utils.getProfileOfType(mUserManager, ProfileSelectFragment.ProfileType.PRIVATE)

View File

@@ -16,18 +16,19 @@
package com.android.settings.applications.credentials;
import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
import com.android.settings.Utils;
public class DefaultWorkCombinedPreferenceController extends DefaultCombinedPreferenceController {
@Nullable
private final UserHandle mUserHandle;
public DefaultWorkCombinedPreferenceController(Context context) {
super(context);
mUserHandle = Utils.getManagedProfile(mUserManager);
super(context, /*isWorkProfile=*/ true, /*isPrivateSpace=*/ false);
mUserHandle = UserUtils.getManagedProfile(mUserManager);
}
@Override
@@ -47,9 +48,4 @@ public class DefaultWorkCombinedPreferenceController extends DefaultCombinedPref
protected void startActivity(Intent intent) {
mContext.startActivityAsUser(intent, mUserHandle);
}
@Override
protected int getUser() {
return mUserHandle.getIdentifier();
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2024 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.annotation.Nullable;
import android.content.Context;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
import com.android.settings.Utils;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
import java.util.List;
/** Handles user related utils. */
public class UserUtils {
public static final String EXTRA_IS_WORK_PROFILE = "isWorkProfile";
public static final String EXTRA_IS_PRIVATE_SPACE = "isPrivateSpace";
/**
* Returns the managed profile of the current user or {@code null} if none is found or a profile
* exists but it is disabled.
*/
@Nullable
public static UserHandle getManagedProfile(UserManager userManager) {
final List<UserHandle> userProfiles = userManager.getUserProfiles();
for (UserHandle profile : userProfiles) {
final UserInfo userInfo = userManager.getUserInfo(profile.getIdentifier());
if (userInfo.isManagedProfile()) {
return profile;
}
}
return null;
}
public static int getUser(boolean isWorkProfile, boolean isPrivateSpace, Context context) {
int profileType = ProfileSelectFragment.ProfileType.PERSONAL;
if (isWorkProfile) {
profileType = ProfileSelectFragment.ProfileType.WORK;
} else if (isPrivateSpace) {
profileType = ProfileSelectFragment.ProfileType.PRIVATE;
}
// Get the user information of the tab we are trying to populate as the tab being populated
// might be different from the current userId
UserHandle userHandle = Utils.getProfileOfType(UserManager.get(context), profileType);
if (userHandle != null) {
return userHandle.getIdentifier();
}
return UserHandle.myUserId();
}
}

View File

@@ -57,7 +57,7 @@ public class CredentialsPickerActivityTest {
@Test
public void testInjectFragmentIntoIntent_normalProfile() {
Intent intent = new Intent();
CredentialsPickerActivity.injectFragmentIntoIntent(mMockContext, intent);
CredentialsPickerActivity.injectFragmentIntoIntent(mMockContext, intent, 10);
assertThat(intent.getStringExtra(CredentialsPickerActivity.EXTRA_SHOW_FRAGMENT))
.isEqualTo(DefaultCombinedPicker.class.getName());
}
@@ -70,7 +70,7 @@ public class CredentialsPickerActivityTest {
when(mUserManager.isManagedProfile(anyInt())).thenReturn(true);
assertThat(DefaultCombinedPickerWork.isUserHandledByFragment(mUserManager, 10)).isTrue();
CredentialsPickerActivity.injectFragmentIntoIntent(mMockContext, intent);
CredentialsPickerActivity.injectFragmentIntoIntent(mMockContext, intent, 10);
assertThat(intent.getStringExtra(CredentialsPickerActivity.EXTRA_SHOW_FRAGMENT))
.isEqualTo(DefaultCombinedPickerWork.class.getName());
}
@@ -84,7 +84,7 @@ public class CredentialsPickerActivityTest {
doReturn(true).when(mUserManager).isPrivateProfile();
assertThat(DefaultCombinedPickerPrivate.isUserHandledByFragment(mUserManager)).isTrue();
CredentialsPickerActivity.injectFragmentIntoIntent(mMockContext, intent);
CredentialsPickerActivity.injectFragmentIntoIntent(mMockContext, intent, 10);
assertThat(intent.getStringExtra(CredentialsPickerActivity.EXTRA_SHOW_FRAGMENT))
.isEqualTo(DefaultCombinedPickerPrivate.class.getName());
}

View File

@@ -69,7 +69,7 @@ public class DefaultCombinedPreferenceControllerTest {
// The setting intent should be null for the new design since this
// is handled by the delegate for the PrimaryProviderPreference.
DefaultCombinedPreferenceController dcpc =
new DefaultCombinedPreferenceController(mContext);
new DefaultCombinedPreferenceController(mContext, false, false);
assertThat(dcpc.getSettingIntent(null).getPackage()).isNull();
}
@@ -81,7 +81,7 @@ public class DefaultCombinedPreferenceControllerTest {
// For the old design the setting intent should still be used.
DefaultCombinedPreferenceController dcpc =
new DefaultCombinedPreferenceController(mContext);
new DefaultCombinedPreferenceController(mContext, false, false);
assertThat(dcpc.getSettingIntent(null).getPackage()).isNotNull();
}
@@ -104,7 +104,7 @@ public class DefaultCombinedPreferenceControllerTest {
}
DefaultCombinedPreferenceController dcpc =
new DefaultCombinedPreferenceController(mContext);
new DefaultCombinedPreferenceController(mContext, false, false);
PrimaryProviderPreference ppp = createTestPreference();
Drawable appIcon = mContext.getResources().getDrawable(R.drawable.ic_settings_delete);