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

Commit 7cfe304e authored by Olivier Nshimiye's avatar Olivier Nshimiye Committed by Android (Google) Code Review
Browse files

Merge "Add resolver sheet support for private profile" into main

parents e9d4b631 91fe9133
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -64,3 +64,10 @@ flag {
    bug: "296829976"
    is_fixed_read_only: true
}

flag {
    name: "allow_resolver_sheet_for_private_space"
    namespace: "profile_experiences"
    description: "Add support for Private Space in resolver sheet"
    bug: "307515485"
}
 No newline at end of file
+45 −6
Original line number Diff line number Diff line
@@ -249,6 +249,7 @@ public class ResolverActivity extends Activity implements

    private UserHandle mCloneProfileUserHandle;
    private UserHandle mTabOwnerUserHandleForLaunch;
    private UserHandle mPrivateProfileUserHandle;

    protected final LatencyTracker mLatencyTracker = getLatencyTracker();

@@ -441,6 +442,7 @@ public class ResolverActivity extends Activity implements
        mPersonalProfileUserHandle = fetchPersonalProfileUserHandle();
        mWorkProfileUserHandle = fetchWorkProfileUserProfile();
        mCloneProfileUserHandle = fetchCloneProfileUserHandle();
        mPrivateProfileUserHandle = fetchPrivateProfileUserHandle();
        mTabOwnerUserHandleForLaunch = fetchTabOwnerUserHandleForLaunch();

        // The last argument of createResolverListAdapter is whether to do special handling
@@ -648,7 +650,8 @@ public class ResolverActivity extends Activity implements
                initialIntents,
                rList,
                filterLastUsed,
                /* userHandle */ getPersonalProfileUserHandle());
                getPersonalProfileUserHandle());

        QuietModeManager quietModeManager = createQuietModeManager();
        return new ResolverMultiProfilePagerAdapter(
                /* context */ this,
@@ -747,6 +750,9 @@ public class ResolverActivity extends Activity implements
    }

    protected UserHandle getPersonalProfileUserHandle() {
        if (privateSpaceEnabled() && isLaunchedAsPrivateProfile()){
            return mPrivateProfileUserHandle;
        }
        return mPersonalProfileUserHandle;
    }
    protected @Nullable UserHandle getWorkProfileUserHandle() {
@@ -761,6 +767,10 @@ public class ResolverActivity extends Activity implements
        return mTabOwnerUserHandleForLaunch;
    }

    protected UserHandle getPrivateProfileUserHandle() {
        return mPrivateProfileUserHandle;
    }

    protected UserHandle fetchPersonalProfileUserHandle() {
        // ActivityManager.getCurrentUser() refers to the current Foreground user. When clone/work
        // profile is active, we always make the personal tab from the foreground user.
@@ -795,12 +805,28 @@ public class ResolverActivity extends Activity implements
        return mCloneProfileUserHandle;
    }

    protected @Nullable UserHandle fetchPrivateProfileUserHandle() {
        mPrivateProfileUserHandle = null;
        UserManager userManager = getSystemService(UserManager.class);
        for (final UserInfo userInfo :
                userManager.getProfiles(mPersonalProfileUserHandle.getIdentifier())) {
            if (userInfo.isPrivateProfile()) {
                mPrivateProfileUserHandle = userInfo.getUserHandle();
                break;
            }
        }
        return mPrivateProfileUserHandle;
    }

    private UserHandle fetchTabOwnerUserHandleForLaunch() {
        // If we are in work profile's process, return WorkProfile user as owner, otherwise we
        // always return PersonalProfile user as owner
        return UserHandle.of(UserHandle.myUserId()).equals(getWorkProfileUserHandle())
                ? getWorkProfileUserHandle()
                : getPersonalProfileUserHandle();
        // If we are in work or private profile's process, return WorkProfile/PrivateProfile user
        // as owner, otherwise we always return PersonalProfile user as owner
        if (UserHandle.of(UserHandle.myUserId()).equals(getWorkProfileUserHandle())) {
            return getWorkProfileUserHandle();
        } else if (privateSpaceEnabled() && isLaunchedAsPrivateProfile()) {
            return getPrivateProfileUserHandle();
        }
        return getPersonalProfileUserHandle();
    }

    private boolean hasWorkProfile() {
@@ -816,7 +842,15 @@ public class ResolverActivity extends Activity implements
                && (UserHandle.myUserId() == getCloneProfileUserHandle().getIdentifier());
    }

    protected final boolean isLaunchedAsPrivateProfile() {
        return getPrivateProfileUserHandle() != null
                && (UserHandle.myUserId() == getPrivateProfileUserHandle().getIdentifier());
    }

    protected boolean shouldShowTabs() {
        if (privateSpaceEnabled() && isLaunchedAsPrivateProfile()) {
            return false;
        }
        return hasWorkProfile() && ENABLE_TABBED_VIEW;
    }

@@ -2619,6 +2653,11 @@ public class ResolverActivity extends Activity implements
        return resolveInfo.userHandle;
    }

    private boolean privateSpaceEnabled() {
        return mIsIntentPicker && android.os.Flags.allowPrivateProfile()
                && android.multiuser.Flags.allowResolverSheetForPrivateSpace();
    }

    /**
     * An a11y delegate that expands resolver drawer when gesture navigation reaches a partially
     * invisible target in the list.
+108 −1
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import static com.android.internal.app.MatcherUtils.first;
import static com.android.internal.app.ResolverDataProvider.createPackageManagerMockedInfo;
import static com.android.internal.app.ResolverWrapperActivity.sOverrides;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;

import static org.hamcrest.CoreMatchers.allOf;
@@ -46,6 +47,7 @@ import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.RemoteException;
import android.os.UserHandle;
import android.platform.test.flag.junit.SetFlagsRule;
import android.text.TextUtils;
import android.view.View;
import android.widget.RelativeLayout;
@@ -88,7 +90,8 @@ public class ResolverActivityTest {
    public ActivityTestRule<ResolverWrapperActivity> mActivityRule =
            new ActivityTestRule<>(ResolverWrapperActivity.class, false,
                    false);

    @Rule
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
    @Before
    public void cleanOverrideData() {
        sOverrides.reset();
@@ -1156,6 +1159,97 @@ public class ResolverActivityTest {
                sOverrides.cloneProfileUserHandle)));
    }

    @Test
    public void testTriggerFromPrivateProfile_withoutWorkProfile() throws RemoteException {
        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
                android.multiuser.Flags.FLAG_ALLOW_RESOLVER_SHEET_FOR_PRIVATE_SPACE);
        markPrivateProfileUserAvailable();
        Intent sendIntent = createSendImageIntent();
        List<ResolvedComponentInfo> privateResolvedComponentInfos =
                createResolvedComponentsForTest(3, sOverrides.privateProfileUserHandle);
        setupResolverControllers(privateResolvedComponentInfos);
        final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
        waitForIdle();
        onView(withId(R.id.tabs)).check(matches(not(isDisplayed())));
        assertThat(activity.getPersonalListAdapter().getCount(), is(3));
        onView(withId(R.id.button_once)).check(matches(not(isEnabled())));
        onView(withId(R.id.button_always)).check(matches(not(isEnabled())));
        for (ResolvedComponentInfo resolvedInfo : privateResolvedComponentInfos) {
            assertEquals(resolvedInfo.getResolveInfoAt(0).userHandle,
                    sOverrides.privateProfileUserHandle);
        }
    }

    @Test
    public void testTriggerFromPrivateProfile_withWorkProfilePresent(){
        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
                android.multiuser.Flags.FLAG_ALLOW_RESOLVER_SHEET_FOR_PRIVATE_SPACE);
        ResolverActivity.ENABLE_TABBED_VIEW = false;
        markPrivateProfileUserAvailable();
        markWorkProfileUserAvailable();
        Intent sendIntent = createSendImageIntent();
        List<ResolvedComponentInfo> privateResolvedComponentInfos =
                createResolvedComponentsForTest(3, sOverrides.privateProfileUserHandle);
        setupResolverControllers(privateResolvedComponentInfos);
        final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
        waitForIdle();
        assertThat(activity.getPersonalListAdapter().getCount(), is(3));
        onView(withId(R.id.tabs)).check(matches(not(isDisplayed())));
        assertEquals(activity.getMultiProfilePagerAdapterCount(), 1);
        for (ResolvedComponentInfo resolvedInfo : privateResolvedComponentInfos) {
            assertEquals(resolvedInfo.getResolveInfoAt(0).userHandle,
                    sOverrides.privateProfileUserHandle);
        }
    }

    @Test
    public void testPrivateProfile_triggerFromPrimaryUser_withWorkProfilePresent(){
        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
                android.multiuser.Flags.FLAG_ALLOW_RESOLVER_SHEET_FOR_PRIVATE_SPACE);
        markPrivateProfileUserAvailable();
        markWorkProfileUserAvailable();
        Intent sendIntent = createSendImageIntent();
        List<ResolvedComponentInfo> personalResolvedComponentInfos =
                createResolvedComponentsForTestWithOtherProfile(3, PERSONAL_USER_HANDLE);
        List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
                sOverrides.workProfileUserHandle);
        setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
        final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
        waitForIdle();
        assertThat(activity.getAdapter().getCount(), is(2));
        assertThat(activity.getWorkListAdapter().getCount(), is(4));
        onView(withId(R.id.tabs)).check(matches(isDisplayed()));
        for (ResolvedComponentInfo resolvedInfo : personalResolvedComponentInfos) {
            assertEquals(resolvedInfo.getResolveInfoAt(0).userHandle,
                    activity.getPersonalProfileUserHandle());
        }
    }

    @Test
    public void testPrivateProfile_triggerFromWorkProfile(){
        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
                android.multiuser.Flags.FLAG_ALLOW_RESOLVER_SHEET_FOR_PRIVATE_SPACE);
        markPrivateProfileUserAvailable();
        markWorkProfileUserAvailable();
        Intent sendIntent = createSendImageIntent();

        List<ResolvedComponentInfo> personalResolvedComponentInfos =
                createResolvedComponentsForTestWithOtherProfile(3, PERSONAL_USER_HANDLE);
        List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
                sOverrides.workProfileUserHandle);
        setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
        final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
        waitForIdle();
        assertThat(activity.getAdapter().getCount(), is(2));
        assertThat(activity.getWorkListAdapter().getCount(), is(4));
        onView(withId(R.id.tabs)).check(matches(isDisplayed()));
        for (ResolvedComponentInfo resolvedInfo : personalResolvedComponentInfos) {
            assertTrue(resolvedInfo.getResolveInfoAt(0).userHandle.equals(
                    activity.getPersonalProfileUserHandle()) || resolvedInfo.getResolveInfoAt(
                    0).userHandle.equals(activity.getWorkProfileUserHandle()));
        }
    }

    private Intent createSendImageIntent() {
        Intent sendIntent = new Intent();
        sendIntent.setAction(Intent.ACTION_SEND);
@@ -1237,6 +1331,10 @@ public class ResolverActivityTest {
        ResolverWrapperActivity.sOverrides.cloneProfileUserHandle = UserHandle.of(11);
    }

    private void markPrivateProfileUserAvailable() {
        ResolverWrapperActivity.sOverrides.privateProfileUserHandle = UserHandle.of(12);
    }

    private void setupResolverControllers(
            List<ResolvedComponentInfo> personalResolvedComponentInfos,
            List<ResolvedComponentInfo> workResolvedComponentInfos) {
@@ -1256,4 +1354,13 @@ public class ResolverActivityTest {
                eq(UserHandle.SYSTEM)))
                .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
    }

    private void setupResolverControllers(
            List<ResolvedComponentInfo> resolvedComponentInfos) {
        when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
                Mockito.anyBoolean(),
                Mockito.anyBoolean(),
                Mockito.isA(List.class)))
                .thenReturn(new ArrayList<>(resolvedComponentInfos));
    }
}
+11 −0
Original line number Diff line number Diff line
@@ -88,6 +88,10 @@ public class ResolverWrapperActivity extends ResolverActivity {
        return ((ResolverListAdapter) mMultiProfilePagerAdapter.getAdapterForIndex(1));
    }

    int getMultiProfilePagerAdapterCount(){
        return mMultiProfilePagerAdapter.getCount();
    }

    @Override
    public boolean isVoiceInteraction() {
        if (sOverrides.isVoiceInteraction != null) {
@@ -143,6 +147,11 @@ public class ResolverWrapperActivity extends ResolverActivity {
        return sOverrides.cloneProfileUserHandle;
    }

    @Override
    protected UserHandle getPrivateProfileUserHandle() {
        return sOverrides.privateProfileUserHandle;
    }

    @Override
    protected UserHandle getTabOwnerUserHandleForLaunch() {
        if (sOverrides.tabOwnerUserHandleForLaunch == null) {
@@ -176,6 +185,7 @@ public class ResolverWrapperActivity extends ResolverActivity {
        public Boolean isVoiceInteraction;
        public UserHandle workProfileUserHandle;
        public UserHandle cloneProfileUserHandle;
        public UserHandle privateProfileUserHandle;
        public UserHandle tabOwnerUserHandleForLaunch;
        public Integer myUserId;
        public boolean hasCrossProfileIntents;
@@ -191,6 +201,7 @@ public class ResolverWrapperActivity extends ResolverActivity {
            workResolverListController = mock(ResolverListController.class);
            workProfileUserHandle = null;
            cloneProfileUserHandle = null;
            privateProfileUserHandle = null;
            tabOwnerUserHandleForLaunch = null;
            myUserId = null;
            hasCrossProfileIntents = true;