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

Commit dfa33126 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Show other profile tab if 0 apps in current profile and >1 in the...

Merge "Show other profile tab if 0 apps in current profile and >1 in the other." into rvc-dev am: 2dda126b am: 8c3dca9e am: 19eeab2a

Change-Id: I153cafc7b59ed93689102ded5330c8dac7600512
parents 425241dc 19eeab2a
Loading
Loading
Loading
Loading
+39 −20
Original line number Original line Diff line number Diff line
@@ -300,30 +300,26 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
    }
    }


    private boolean rebuildTab(ResolverListAdapter activeListAdapter, boolean doPostProcessing) {
    private boolean rebuildTab(ResolverListAdapter activeListAdapter, boolean doPostProcessing) {
        UserHandle listUserHandle = activeListAdapter.getUserHandle();
        if (shouldShowNoCrossProfileIntentsEmptyState(activeListAdapter)) {

            activeListAdapter.postListReadyRunnable(doPostProcessing);
        if (UserHandle.myUserId() != listUserHandle.getIdentifier()) {
            if (!mInjector.hasCrossProfileIntents(activeListAdapter.getIntents(),
                    UserHandle.myUserId(), listUserHandle.getIdentifier())) {
                if (listUserHandle.equals(mPersonalProfileUserHandle)) {
                    DevicePolicyEventLogger.createEvent(
                                DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL)
                            .setStrings(getMetricsCategory())
                            .write();
                    showNoWorkToPersonalIntentsEmptyState(activeListAdapter);
                } else {
                    DevicePolicyEventLogger.createEvent(
                            DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK)
                            .setStrings(getMetricsCategory())
                            .write();
                    showNoPersonalToWorkIntentsEmptyState(activeListAdapter);
                }
            return false;
            return false;
        }
        }
        }
        return activeListAdapter.rebuildList(doPostProcessing);
        return activeListAdapter.rebuildList(doPostProcessing);
    }
    }


    private boolean shouldShowNoCrossProfileIntentsEmptyState(
            ResolverListAdapter activeListAdapter) {
        UserHandle listUserHandle = activeListAdapter.getUserHandle();
        return UserHandle.myUserId() != listUserHandle.getIdentifier()
                && allowShowNoCrossProfileIntentsEmptyState()
                && !mInjector.hasCrossProfileIntents(activeListAdapter.getIntents(),
                        UserHandle.myUserId(), listUserHandle.getIdentifier());
    }

    boolean allowShowNoCrossProfileIntentsEmptyState() {
        return true;
    }

    protected abstract void showWorkProfileOffEmptyState(
    protected abstract void showWorkProfileOffEmptyState(
            ResolverListAdapter activeListAdapter, View.OnClickListener listener);
            ResolverListAdapter activeListAdapter, View.OnClickListener listener);


@@ -353,12 +349,35 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
     * anyway.
     * anyway.
     */
     */
    void showEmptyResolverListEmptyState(ResolverListAdapter listAdapter) {
    void showEmptyResolverListEmptyState(ResolverListAdapter listAdapter) {
        if (maybeShowNoCrossProfileIntentsEmptyState(listAdapter)) {
            return;
        }
        if (maybeShowWorkProfileOffEmptyState(listAdapter)) {
        if (maybeShowWorkProfileOffEmptyState(listAdapter)) {
            return;
            return;
        }
        }
        maybeShowNoAppsAvailableEmptyState(listAdapter);
        maybeShowNoAppsAvailableEmptyState(listAdapter);
    }
    }


    private boolean maybeShowNoCrossProfileIntentsEmptyState(ResolverListAdapter listAdapter) {
        if (!shouldShowNoCrossProfileIntentsEmptyState(listAdapter)) {
            return false;
        }
        if (listAdapter.getUserHandle().equals(mPersonalProfileUserHandle)) {
            DevicePolicyEventLogger.createEvent(
                    DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL)
                    .setStrings(getMetricsCategory())
                    .write();
            showNoWorkToPersonalIntentsEmptyState(listAdapter);
        } else {
            DevicePolicyEventLogger.createEvent(
                    DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK)
                    .setStrings(getMetricsCategory())
                    .write();
            showNoPersonalToWorkIntentsEmptyState(listAdapter);
        }
        return true;
    }

    /**
    /**
     * Returns {@code true} if the work profile off empty state screen is shown.
     * Returns {@code true} if the work profile off empty state screen is shown.
     */
     */
+45 −11
Original line number Original line Diff line number Diff line
@@ -179,6 +179,7 @@ public class ResolverActivity extends Activity implements
    public static final String EXTRA_IS_AUDIO_CAPTURE_DEVICE = "is_audio_capture_device";
    public static final String EXTRA_IS_AUDIO_CAPTURE_DEVICE = "is_audio_capture_device";


    private BroadcastReceiver mWorkProfileStateReceiver;
    private BroadcastReceiver mWorkProfileStateReceiver;
    private boolean mIsHeaderCreated;


    /**
    /**
     * Get the string resource to be used as a label for the link to the resolver activity for an
     * Get the string resource to be used as a label for the link to the resolver activity for an
@@ -479,13 +480,42 @@ public class ResolverActivity extends Activity implements
                        == workProfileUserHandle.getIdentifier()),
                        == workProfileUserHandle.getIdentifier()),
                mUseLayoutForBrowsables,
                mUseLayoutForBrowsables,
                /* userHandle */ workProfileUserHandle);
                /* userHandle */ workProfileUserHandle);
        // In the edge case when we have 0 apps in the current profile and >1 apps in the other,
        // the intent resolver is started in the other profile. Since this is the only case when
        // this happens, we check for it here and set the current profile's tab.
        int selectedProfile = getCurrentProfile();
        UserHandle intentUser = UserHandle.of(getLaunchingUserId());
        if (!getUser().equals(intentUser)) {
            if (getPersonalProfileUserHandle().equals(intentUser)) {
                selectedProfile = PROFILE_PERSONAL;
            } else if (getWorkProfileUserHandle().equals(intentUser)) {
                selectedProfile = PROFILE_WORK;
            }
        }
        return new ResolverMultiProfilePagerAdapter(
        return new ResolverMultiProfilePagerAdapter(
                /* context */ this,
                /* context */ this,
                personalAdapter,
                personalAdapter,
                workAdapter,
                workAdapter,
                /* defaultProfile */ getCurrentProfile(),
                selectedProfile,
                getPersonalProfileUserHandle(),
                getPersonalProfileUserHandle(),
                getWorkProfileUserHandle());
                getWorkProfileUserHandle(),
                /* shouldShowNoCrossProfileIntentsEmptyState= */ getUser().equals(intentUser));
    }

    /**
     * Returns the user id of the user that the starting intent originated from.
     * <p>This is not necessarily equal to {@link #getUserId()} or {@link UserHandle#myUserId()},
     * as there are edge cases when the intent resolver is launched in the other profile.
     * For example, when we have 0 resolved apps in current profile and multiple resolved apps
     * in the other profile, opening a link from the current profile launches the intent resolver
     * in the other one. b/148536209 for more info.
     */
    private int getLaunchingUserId() {
        int contentUserHint = getIntent().getContentUserHint();
        if (contentUserHint == UserHandle.USER_CURRENT) {
            return UserHandle.myUserId();
        }
        return contentUserHint;
    }
    }


    protected @Profile int getCurrentProfile() {
    protected @Profile int getCurrentProfile() {
@@ -856,7 +886,7 @@ public class ResolverActivity extends Activity implements


    private void setAlwaysButtonEnabled(boolean hasValidSelection, int checkedPos,
    private void setAlwaysButtonEnabled(boolean hasValidSelection, int checkedPos,
            boolean filtered) {
            boolean filtered) {
        if (mMultiProfilePagerAdapter.getCurrentUserHandle() != getUser()) {
        if (!mMultiProfilePagerAdapter.getCurrentUserHandle().equals(getUser())) {
            // Never allow the inactive profile to always open an app.
            // Never allow the inactive profile to always open an app.
            mAlwaysButton.setEnabled(false);
            mAlwaysButton.setEnabled(false);
            return;
            return;
@@ -995,10 +1025,7 @@ public class ResolverActivity extends Activity implements
            mMultiProfilePagerAdapter.showListView(listAdapter);
            mMultiProfilePagerAdapter.showListView(listAdapter);
        }
        }
        if (doPostProcessing) {
        if (doPostProcessing) {
            if (mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier()
            maybeCreateHeader(listAdapter);
                    == UserHandle.myUserId()) {
                setHeader();
            }
            resetButtonBar();
            resetButtonBar();
            onListRebuilt(listAdapter);
            onListRebuilt(listAdapter);
        }
        }
@@ -1679,10 +1706,15 @@ public class ResolverActivity extends Activity implements


    /**
    /**
     * Configure the area above the app selection list (title, content preview, etc).
     * Configure the area above the app selection list (title, content preview, etc).
     * <p>The header is created once when first launching the activity and whenever a package is
     * installed or uninstalled.
     */
     */
    public void setHeader() {
    private void maybeCreateHeader(ResolverListAdapter listAdapter) {
        if (mMultiProfilePagerAdapter.getActiveListAdapter().getCount() == 0
        if (mIsHeaderCreated) {
                && mMultiProfilePagerAdapter.getActiveListAdapter().getPlaceholderCount() == 0) {
            return;
        }
        if (!shouldShowTabs()
                && listAdapter.getCount() == 0 && listAdapter.getPlaceholderCount() == 0) {
            final TextView titleView = findViewById(R.id.title);
            final TextView titleView = findViewById(R.id.title);
            if (titleView != null) {
            if (titleView != null) {
                titleView.setVisibility(View.GONE);
                titleView.setVisibility(View.GONE);
@@ -1703,8 +1735,9 @@ public class ResolverActivity extends Activity implements


        final ImageView iconView = findViewById(R.id.icon);
        final ImageView iconView = findViewById(R.id.icon);
        if (iconView != null) {
        if (iconView != null) {
            mMultiProfilePagerAdapter.getActiveListAdapter().loadFilteredItemIconTaskAsync(iconView);
            listAdapter.loadFilteredItemIconTaskAsync(iconView);
        }
        }
        mIsHeaderCreated = true;
    }
    }


    protected void resetButtonBar() {
    protected void resetButtonBar() {
@@ -1804,6 +1837,7 @@ public class ResolverActivity extends Activity implements
                // turning on.
                // turning on.
                return;
                return;
            }
            }
            mIsHeaderCreated = false;
            boolean listRebuilt = mMultiProfilePagerAdapter.rebuildActiveTab(true);
            boolean listRebuilt = mMultiProfilePagerAdapter.rebuildActiveTab(true);
            if (listRebuilt) {
            if (listRebuilt) {
                ResolverListAdapter activeListAdapter =
                ResolverListAdapter activeListAdapter =
+10 −1
Original line number Original line Diff line number Diff line
@@ -35,6 +35,7 @@ import com.android.internal.widget.PagerAdapter;
public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerAdapter {
public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerAdapter {


    private final ResolverProfileDescriptor[] mItems;
    private final ResolverProfileDescriptor[] mItems;
    private final boolean mShouldShowNoCrossProfileIntentsEmptyState;


    ResolverMultiProfilePagerAdapter(Context context,
    ResolverMultiProfilePagerAdapter(Context context,
            ResolverListAdapter adapter,
            ResolverListAdapter adapter,
@@ -44,6 +45,7 @@ public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerA
        mItems = new ResolverProfileDescriptor[] {
        mItems = new ResolverProfileDescriptor[] {
                createProfileDescriptor(adapter)
                createProfileDescriptor(adapter)
        };
        };
        mShouldShowNoCrossProfileIntentsEmptyState = true;
    }
    }


    ResolverMultiProfilePagerAdapter(Context context,
    ResolverMultiProfilePagerAdapter(Context context,
@@ -51,13 +53,15 @@ public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerA
            ResolverListAdapter workAdapter,
            ResolverListAdapter workAdapter,
            @Profile int defaultProfile,
            @Profile int defaultProfile,
            UserHandle personalProfileUserHandle,
            UserHandle personalProfileUserHandle,
            UserHandle workProfileUserHandle) {
            UserHandle workProfileUserHandle,
            boolean shouldShowNoCrossProfileIntentsEmptyState) {
        super(context, /* currentPage */ defaultProfile, personalProfileUserHandle,
        super(context, /* currentPage */ defaultProfile, personalProfileUserHandle,
                workProfileUserHandle);
                workProfileUserHandle);
        mItems = new ResolverProfileDescriptor[] {
        mItems = new ResolverProfileDescriptor[] {
                createProfileDescriptor(personalAdapter),
                createProfileDescriptor(personalAdapter),
                createProfileDescriptor(workAdapter)
                createProfileDescriptor(workAdapter)
        };
        };
        mShouldShowNoCrossProfileIntentsEmptyState = shouldShowNoCrossProfileIntentsEmptyState;
    }
    }


    private ResolverProfileDescriptor createProfileDescriptor(
    private ResolverProfileDescriptor createProfileDescriptor(
@@ -162,6 +166,11 @@ public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerA
        return ResolverActivity.METRICS_CATEGORY_RESOLVER;
        return ResolverActivity.METRICS_CATEGORY_RESOLVER;
    }
    }


    @Override
    boolean allowShowNoCrossProfileIntentsEmptyState() {
        return mShouldShowNoCrossProfileIntentsEmptyState;
    }

    @Override
    @Override
    protected void showWorkProfileOffEmptyState(ResolverListAdapter activeListAdapter,
    protected void showWorkProfileOffEmptyState(ResolverListAdapter activeListAdapter,
            View.OnClickListener listener) {
            View.OnClickListener listener) {
+55 −0
Original line number Original line Diff line number Diff line
@@ -38,13 +38,16 @@ import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertFalse;


import android.content.Intent;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.UserHandle;
import android.os.UserHandle;
import android.text.TextUtils;
import android.text.TextUtils;
import android.view.View;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;


import androidx.test.InstrumentationRegistry;
import androidx.test.InstrumentationRegistry;
import androidx.test.espresso.Espresso;
import androidx.test.espresso.Espresso;
@@ -543,6 +546,51 @@ public class ResolverActivityTest {
        assertThat(activity.getWorkListAdapter().getCount(), is(4));
        assertThat(activity.getWorkListAdapter().getCount(), is(4));
    }
    }


    @Test
    public void testWorkTab_headerIsVisibleInPersonalTab() {
        // enable the work tab feature flag
        ResolverActivity.ENABLE_TABBED_VIEW = true;
        markWorkProfileUserAvailable();
        List<ResolvedComponentInfo> personalResolvedComponentInfos =
                createResolvedComponentsForTestWithOtherProfile(1);
        List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
        setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
        Intent sendIntent = createOpenWebsiteIntent();

        final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
        waitForIdle();
        TextView headerText = activity.findViewById(R.id.title);
        String initialText = headerText.getText().toString();
        assertFalse(initialText.isEmpty(), "Header text is empty.");
        assertThat(headerText.getVisibility(), is(View.VISIBLE));
    }

    @Test
    public void testWorkTab_switchTabs_headerStaysSame() {
        // enable the work tab feature flag
        ResolverActivity.ENABLE_TABBED_VIEW = true;
        markWorkProfileUserAvailable();
        List<ResolvedComponentInfo> personalResolvedComponentInfos =
                createResolvedComponentsForTestWithOtherProfile(1);
        List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
        setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
        Intent sendIntent = createOpenWebsiteIntent();

        final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
        waitForIdle();
        TextView headerText = activity.findViewById(R.id.title);
        String initialText = headerText.getText().toString();
        onView(withText(R.string.resolver_work_tab))
                .perform(click());

        waitForIdle();
        String currentText = headerText.getText().toString();
        assertThat(headerText.getVisibility(), is(View.VISIBLE));
        assertThat(String.format("Header text is not the same when switching tabs, personal profile"
                        + " header was %s but work profile header is %s", initialText, currentText),
                TextUtils.equals(initialText, currentText));
    }

    @Ignore // b/148156663
    @Ignore // b/148156663
    @Test
    @Test
    public void testWorkTab_noPersonalApps_canStartWorkApps()
    public void testWorkTab_noPersonalApps_canStartWorkApps()
@@ -761,6 +809,13 @@ public class ResolverActivityTest {
        return sendIntent;
        return sendIntent;
    }
    }


    private Intent createOpenWebsiteIntent() {
        Intent sendIntent = new Intent();
        sendIntent.setAction(Intent.ACTION_VIEW);
        sendIntent.setData(Uri.parse("https://google.com"));
        return sendIntent;
    }

    private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults) {
    private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults) {
        List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
        List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
        for (int i = 0; i < numberOfResults; i++) {
        for (int i = 0; i < numberOfResults; i++) {