Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d4ce558f authored by Ahaan Ugale's avatar Ahaan Ugale
Browse files

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
parent f0d8071b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
        android:persistent="false"
        android:title="@string/autofill_passwords"
        settings:controller="com.android.settings.applications.autofill.PasswordsPreferenceController"
        settings:forWork="true"
        settings:keywords="@string/autofill_keywords" />

    <com.android.settings.widget.WorkOnlyCategory
+31 −18
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.widget.AppPreference;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

@@ -76,28 +77,30 @@ public class PasswordsPreferenceController extends BasePreferenceController
    private LifecycleOwner mLifecycleOwner;

    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);
        mPm = context.getPackageManager();
        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--) {
            final String passwordsActivity = availableServices.get(i).getPasswordsActivity();
            if (TextUtils.isEmpty(passwordsActivity)) {
                availableServices.remove(i);
            }
        }
        mServices = availableServices;
    }

    @OnLifecycleEvent(ON_CREATE)
    void onCreate(LifecycleOwner lifecycleOwner) {
        mLifecycleOwner = lifecycleOwner;
        // TODO: Reverse the loop above and add to mServices directly.
        mServices.clear();
        mServices.addAll(availableServices);
    }

    @Override
@@ -109,8 +112,7 @@ public class PasswordsPreferenceController extends BasePreferenceController
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        final PreferenceGroup group = screen.findPreference(getPreferenceKey());
        // TODO(b/169455298): Show work profile passwords too.
        addPasswordPreferences(screen.getContext(), UserHandle.myUserId(), group);
        addPasswordPreferences(screen.getContext(), getUser(), group);
    }

    private void addPasswordPreferences(
@@ -126,9 +128,15 @@ public class PasswordsPreferenceController extends BasePreferenceController
                            serviceInfo.applicationInfo,
                            user);
            pref.setIcon(Utils.getSafeIcon(icon));
            pref.setIntent(
            pref.setOnPreferenceClickListener(p -> {
                final Intent intent =
                        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.
            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();
    }
}
+31 −7
Original line number Diff line number Diff line
@@ -21,11 +21,19 @@ import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_U

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.spy;
import static org.mockito.Mockito.verify;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Looper;
import android.os.UserHandle;
import android.service.autofill.AutofillServiceInfo;

import androidx.lifecycle.Lifecycle;
@@ -40,9 +48,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.collect.Lists;

import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;

import java.util.Collections;
import java.util.List;
@@ -56,7 +64,7 @@ public class PasswordsPreferenceControllerTest {

    @Before
    public void setUp() {
        mContext = ApplicationProvider.getApplicationContext();
        mContext = spy(ApplicationProvider.getApplicationContext());
        if (Looper.myLooper() == null) {
            Looper.prepare(); // needed to create the preference screen
        }
@@ -66,6 +74,15 @@ public class PasswordsPreferenceControllerTest {
        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
    public void getAvailabilityStatus_noServices_returnsUnavailable() {
        PasswordsPreferenceController controller =
@@ -105,21 +122,26 @@ public class PasswordsPreferenceControllerTest {
        assertThat(mPasswordsPreferenceCategory.getPreferenceCount()).isEqualTo(0);
    }

    @Ignore("TODO: Fix the test to handle the service binding.")
    @Test
    @UiThreadTest
    public void displayPreference_withPasswords_addsPreference() {
        AutofillServiceInfo service = createServiceWithPasswords();
        service.getServiceInfo().packageName = "";
        service.getServiceInfo().name = "";
        PasswordsPreferenceController controller =
                createControllerWithServices(Lists.newArrayList(service));
        controller.onCreate(() -> mock(Lifecycle.class));
        doReturn(false).when(mContext).bindServiceAsUser(any(), any(), anyInt(), any());

        controller.displayPreference(mScreen);

        assertThat(mPasswordsPreferenceCategory.getPreferenceCount()).isEqualTo(1);
        Preference pref = mPasswordsPreferenceCategory.getPreference(0);
        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(
                        new ComponentName(
                                service.getServiceInfo().packageName,
@@ -128,8 +150,10 @@ public class PasswordsPreferenceControllerTest {

    private PasswordsPreferenceController createControllerWithServices(
            List<AutofillServiceInfo> availableServices) {
        return new PasswordsPreferenceController(
                mContext, mPasswordsPreferenceCategory.getKey(), availableServices);
        PasswordsPreferenceController controller =
                new PasswordsPreferenceController(mContext, mPasswordsPreferenceCategory.getKey());
        controller.init(() -> mock(Lifecycle.class), availableServices);
        return controller;
    }

    private AutofillServiceInfo createServiceWithPasswords() {