Password settings: Fix work profile
Currently, the work profile password settings just point to the personal profile app. This change fixes this using the forWork metadata tag, that sets the work profile user in BasePreferenceController. Also fixes and re-enables the displayPreference_withPasswords_addsPreference test. Fix: 192417100 Test: manual - work profile link works, password count is accurate Test: atest PasswordsPreferenceControllerTest Change-Id: I6345b69b9c03ff13b8e2784e69dc0188abc436e3
This commit is contained in:
@@ -28,6 +28,7 @@
|
|||||||
android:persistent="false"
|
android:persistent="false"
|
||||||
android:title="@string/autofill_passwords"
|
android:title="@string/autofill_passwords"
|
||||||
settings:controller="com.android.settings.applications.autofill.PasswordsPreferenceController"
|
settings:controller="com.android.settings.applications.autofill.PasswordsPreferenceController"
|
||||||
|
settings:forWork="true"
|
||||||
settings:keywords="@string/autofill_keywords" />
|
settings:keywords="@string/autofill_keywords" />
|
||||||
|
|
||||||
<com.android.settings.widget.WorkOnlyCategory
|
<com.android.settings.widget.WorkOnlyCategory
|
||||||
|
@@ -55,6 +55,7 @@ import com.android.settings.core.BasePreferenceController;
|
|||||||
import com.android.settingslib.widget.AppPreference;
|
import com.android.settingslib.widget.AppPreference;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
@@ -76,28 +77,30 @@ public class PasswordsPreferenceController extends BasePreferenceController
|
|||||||
private LifecycleOwner mLifecycleOwner;
|
private LifecycleOwner mLifecycleOwner;
|
||||||
|
|
||||||
public PasswordsPreferenceController(Context context, String preferenceKey) {
|
public PasswordsPreferenceController(Context context, String preferenceKey) {
|
||||||
this(context, preferenceKey,
|
|
||||||
AutofillServiceInfo.getAvailableServices(context, UserHandle.myUserId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
public PasswordsPreferenceController(
|
|
||||||
Context context, String preferenceKey, List<AutofillServiceInfo> availableServices) {
|
|
||||||
super(context, preferenceKey);
|
super(context, preferenceKey);
|
||||||
mPm = context.getPackageManager();
|
mPm = context.getPackageManager();
|
||||||
mIconFactory = IconDrawableFactory.newInstance(mContext);
|
mIconFactory = IconDrawableFactory.newInstance(mContext);
|
||||||
|
mServices = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnLifecycleEvent(ON_CREATE)
|
||||||
|
void onCreate(LifecycleOwner lifecycleOwner) {
|
||||||
|
init(lifecycleOwner, AutofillServiceInfo.getAvailableServices(mContext, getUser()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void init(LifecycleOwner lifecycleOwner, List<AutofillServiceInfo> availableServices) {
|
||||||
|
mLifecycleOwner = lifecycleOwner;
|
||||||
|
|
||||||
for (int i = availableServices.size() - 1; i >= 0; i--) {
|
for (int i = availableServices.size() - 1; i >= 0; i--) {
|
||||||
final String passwordsActivity = availableServices.get(i).getPasswordsActivity();
|
final String passwordsActivity = availableServices.get(i).getPasswordsActivity();
|
||||||
if (TextUtils.isEmpty(passwordsActivity)) {
|
if (TextUtils.isEmpty(passwordsActivity)) {
|
||||||
availableServices.remove(i);
|
availableServices.remove(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mServices = availableServices;
|
// TODO: Reverse the loop above and add to mServices directly.
|
||||||
}
|
mServices.clear();
|
||||||
|
mServices.addAll(availableServices);
|
||||||
@OnLifecycleEvent(ON_CREATE)
|
|
||||||
void onCreate(LifecycleOwner lifecycleOwner) {
|
|
||||||
mLifecycleOwner = lifecycleOwner;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -109,8 +112,7 @@ public class PasswordsPreferenceController extends BasePreferenceController
|
|||||||
public void displayPreference(PreferenceScreen screen) {
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
super.displayPreference(screen);
|
super.displayPreference(screen);
|
||||||
final PreferenceGroup group = screen.findPreference(getPreferenceKey());
|
final PreferenceGroup group = screen.findPreference(getPreferenceKey());
|
||||||
// TODO(b/169455298): Show work profile passwords too.
|
addPasswordPreferences(screen.getContext(), getUser(), group);
|
||||||
addPasswordPreferences(screen.getContext(), UserHandle.myUserId(), group);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPasswordPreferences(
|
private void addPasswordPreferences(
|
||||||
@@ -126,9 +128,15 @@ public class PasswordsPreferenceController extends BasePreferenceController
|
|||||||
serviceInfo.applicationInfo,
|
serviceInfo.applicationInfo,
|
||||||
user);
|
user);
|
||||||
pref.setIcon(Utils.getSafeIcon(icon));
|
pref.setIcon(Utils.getSafeIcon(icon));
|
||||||
pref.setIntent(
|
pref.setOnPreferenceClickListener(p -> {
|
||||||
|
final Intent intent =
|
||||||
new Intent(Intent.ACTION_MAIN)
|
new Intent(Intent.ACTION_MAIN)
|
||||||
.setClassName(serviceInfo.packageName, service.getPasswordsActivity()));
|
.setClassName(
|
||||||
|
serviceInfo.packageName,
|
||||||
|
service.getPasswordsActivity());
|
||||||
|
prefContext.startActivityAsUser(intent, UserHandle.of(user));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
// Set an empty summary to avoid a UI flicker when the value loads.
|
// Set an empty summary to avoid a UI flicker when the value loads.
|
||||||
pref.setSummary(R.string.summary_placeholder);
|
pref.setSummary(R.string.summary_placeholder);
|
||||||
|
|
||||||
@@ -213,4 +221,9 @@ public class PasswordsPreferenceController extends BasePreferenceController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getUser() {
|
||||||
|
UserHandle workUser = getWorkProfileUser();
|
||||||
|
return workUser != null ? workUser.getIdentifier() : UserHandle.myUserId();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -21,11 +21,19 @@ import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_U
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.os.UserHandle;
|
||||||
import android.service.autofill.AutofillServiceInfo;
|
import android.service.autofill.AutofillServiceInfo;
|
||||||
|
|
||||||
import androidx.lifecycle.Lifecycle;
|
import androidx.lifecycle.Lifecycle;
|
||||||
@@ -40,9 +48,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|||||||
import com.google.android.collect.Lists;
|
import com.google.android.collect.Lists;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -56,7 +64,7 @@ public class PasswordsPreferenceControllerTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
mContext = ApplicationProvider.getApplicationContext();
|
mContext = spy(ApplicationProvider.getApplicationContext());
|
||||||
if (Looper.myLooper() == null) {
|
if (Looper.myLooper() == null) {
|
||||||
Looper.prepare(); // needed to create the preference screen
|
Looper.prepare(); // needed to create the preference screen
|
||||||
}
|
}
|
||||||
@@ -66,6 +74,15 @@ public class PasswordsPreferenceControllerTest {
|
|||||||
mScreen.addPreference(mPasswordsPreferenceCategory);
|
mScreen.addPreference(mPasswordsPreferenceCategory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
// Tests that getAvailabilityStatus() does not throw an exception if it's called before the
|
||||||
|
// Controller is initialized (this can happen during indexing).
|
||||||
|
public void getAvailabilityStatus_withoutInit_returnsUnavailable() {
|
||||||
|
PasswordsPreferenceController controller =
|
||||||
|
new PasswordsPreferenceController(mContext, mPasswordsPreferenceCategory.getKey());
|
||||||
|
assertThat(controller.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAvailabilityStatus_noServices_returnsUnavailable() {
|
public void getAvailabilityStatus_noServices_returnsUnavailable() {
|
||||||
PasswordsPreferenceController controller =
|
PasswordsPreferenceController controller =
|
||||||
@@ -105,21 +122,26 @@ public class PasswordsPreferenceControllerTest {
|
|||||||
assertThat(mPasswordsPreferenceCategory.getPreferenceCount()).isEqualTo(0);
|
assertThat(mPasswordsPreferenceCategory.getPreferenceCount()).isEqualTo(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("TODO: Fix the test to handle the service binding.")
|
|
||||||
@Test
|
@Test
|
||||||
@UiThreadTest
|
@UiThreadTest
|
||||||
public void displayPreference_withPasswords_addsPreference() {
|
public void displayPreference_withPasswords_addsPreference() {
|
||||||
AutofillServiceInfo service = createServiceWithPasswords();
|
AutofillServiceInfo service = createServiceWithPasswords();
|
||||||
|
service.getServiceInfo().packageName = "";
|
||||||
|
service.getServiceInfo().name = "";
|
||||||
PasswordsPreferenceController controller =
|
PasswordsPreferenceController controller =
|
||||||
createControllerWithServices(Lists.newArrayList(service));
|
createControllerWithServices(Lists.newArrayList(service));
|
||||||
controller.onCreate(() -> mock(Lifecycle.class));
|
doReturn(false).when(mContext).bindServiceAsUser(any(), any(), anyInt(), any());
|
||||||
|
|
||||||
controller.displayPreference(mScreen);
|
controller.displayPreference(mScreen);
|
||||||
|
|
||||||
assertThat(mPasswordsPreferenceCategory.getPreferenceCount()).isEqualTo(1);
|
assertThat(mPasswordsPreferenceCategory.getPreferenceCount()).isEqualTo(1);
|
||||||
Preference pref = mPasswordsPreferenceCategory.getPreference(0);
|
Preference pref = mPasswordsPreferenceCategory.getPreference(0);
|
||||||
assertThat(pref.getIcon()).isNotNull();
|
assertThat(pref.getIcon()).isNotNull();
|
||||||
assertThat(pref.getIntent().getComponent())
|
pref.performClick();
|
||||||
|
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||||
|
UserHandle user = mContext.getUser();
|
||||||
|
verify(mContext).startActivityAsUser(intentCaptor.capture(), eq(user));
|
||||||
|
assertThat(intentCaptor.getValue().getComponent())
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
new ComponentName(
|
new ComponentName(
|
||||||
service.getServiceInfo().packageName,
|
service.getServiceInfo().packageName,
|
||||||
@@ -128,8 +150,10 @@ public class PasswordsPreferenceControllerTest {
|
|||||||
|
|
||||||
private PasswordsPreferenceController createControllerWithServices(
|
private PasswordsPreferenceController createControllerWithServices(
|
||||||
List<AutofillServiceInfo> availableServices) {
|
List<AutofillServiceInfo> availableServices) {
|
||||||
return new PasswordsPreferenceController(
|
PasswordsPreferenceController controller =
|
||||||
mContext, mPasswordsPreferenceCategory.getKey(), availableServices);
|
new PasswordsPreferenceController(mContext, mPasswordsPreferenceCategory.getKey());
|
||||||
|
controller.init(() -> mock(Lifecycle.class), availableServices);
|
||||||
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AutofillServiceInfo createServiceWithPasswords() {
|
private AutofillServiceInfo createServiceWithPasswords() {
|
||||||
|
Reference in New Issue
Block a user