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

Commit d22d1e1f authored by Matt Casey's avatar Matt Casey Committed by Android (Google) Code Review
Browse files

Merge "Add 'miniresolver' UI for cross-profile single app resolution."

parents 0bfb83db 81e474d7
Loading
Loading
Loading
Loading
+77 −2
Original line number Diff line number Diff line
@@ -1011,15 +1011,19 @@ public class ResolverActivity extends Activity implements
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        ViewPager viewPager = findViewById(R.id.profile_pager);
        if (viewPager != null) {
            outState.putInt(LAST_SHOWN_TAB_KEY, viewPager.getCurrentItem());
        }
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        resetButtonBar();
        ViewPager viewPager = findViewById(R.id.profile_pager);
        if (viewPager != null) {
            viewPager.setCurrentItem(savedInstanceState.getInt(LAST_SHOWN_TAB_KEY));
        }
        mMultiProfilePagerAdapter.clearInactiveProfileCache();
    }

@@ -1568,6 +1572,11 @@ public class ResolverActivity extends Activity implements
            rebuildCompleted = rebuildCompleted && rebuildInactiveCompleted;
        }

        if (shouldUseMiniResolver()) {
            configureMiniResolverContent();
            return false;
        }

        if (useLayoutWithDefault()) {
            mLayoutId = R.layout.resolver_list_with_default;
        } else {
@@ -1578,6 +1587,72 @@ public class ResolverActivity extends Activity implements
        return postRebuildList(rebuildCompleted);
    }

    private void configureMiniResolverContent() {
        mLayoutId = R.layout.miniresolver;
        setContentView(mLayoutId);

        DisplayResolveInfo sameProfileResolveInfo =
                mMultiProfilePagerAdapter.getActiveListAdapter().mDisplayList.get(0);
        boolean inWorkProfile = getCurrentProfile() == PROFILE_WORK;

        DisplayResolveInfo otherProfileResolveInfo =
                mMultiProfilePagerAdapter.getInactiveListAdapter().mDisplayList.get(0);
        ImageView icon = findViewById(R.id.icon);
        // TODO: Set icon drawable to app icon.

        ((TextView) findViewById(R.id.open_cross_profile)).setText(
                getResources().getString(
                        inWorkProfile ? R.string.miniresolver_open_in_personal
                                : R.string.miniresolver_open_in_work,
                        otherProfileResolveInfo.getDisplayLabel()));
        ((Button) findViewById(R.id.use_same_profile_browser)).setText(
                inWorkProfile ? R.string.miniresolver_use_work_browser
                        : R.string.miniresolver_use_personal_browser);

        findViewById(R.id.use_same_profile_browser).setOnClickListener(
                v -> safelyStartActivity(sameProfileResolveInfo));

        findViewById(R.id.button_open).setOnClickListener(v -> {
            Intent intent = otherProfileResolveInfo.getResolvedIntent();
            if (intent != null) {
                prepareIntentForCrossProfileLaunch(intent);
            }
            safelyStartActivityInternal(otherProfileResolveInfo,
                    mMultiProfilePagerAdapter.getInactiveListAdapter().mResolverListController
                            .getUserHandle());
        });
    }

    private boolean shouldUseMiniResolver() {
        if (mMultiProfilePagerAdapter.getActiveListAdapter() == null
                || mMultiProfilePagerAdapter.getInactiveListAdapter() == null) {
            return false;
        }
        List<DisplayResolveInfo> sameProfileList =
                mMultiProfilePagerAdapter.getActiveListAdapter().mDisplayList;
        List<DisplayResolveInfo> otherProfileList =
                mMultiProfilePagerAdapter.getInactiveListAdapter().mDisplayList;

        if (otherProfileList.size() != 1) {
            Log.d(TAG, "Found " + otherProfileList.size() + " resolvers in the other profile");
            return false;
        }

        if (otherProfileList.get(0).getResolveInfo().handleAllWebDataURI) {
            Log.d(TAG, "Other profile is a web browser");
            return false;
        }

        for (DisplayResolveInfo info : sameProfileList) {
            if (!info.getResolveInfo().handleAllWebDataURI) {
                Log.d(TAG, "Non-browser found in this profile");
                return false;
            }
        }

        return true;
    }

    /**
     * Finishing procedures to be performed after the list has been rebuilt.
     * </p>Subclasses must call postRebuildListInternal at the end of postRebuildList.
+111 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright (C) 2022 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.
  -->
<com.android.internal.widget.ResolverDrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:maxWidth="@dimen/resolver_max_width"
    android:maxCollapsedHeight="@dimen/resolver_max_collapsed_height"
    android:maxCollapsedHeightSmall="56dp"
    android:id="@id/contentPanel">

    <RelativeLayout
        android:id="@+id/title_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alwaysShow="true"
        android:elevation="@dimen/resolver_elevation"
        android:paddingTop="@dimen/resolver_small_margin"
        android:paddingStart="@dimen/resolver_edge_margin"
        android:paddingEnd="@dimen/resolver_edge_margin"
        android:paddingBottom="@dimen/resolver_title_padding_bottom"
        android:background="@drawable/bottomsheet_background">

        <ImageView
            android:id="@+id/icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
        />

        <TextView
            android:id="@+id/open_cross_profile"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/icon"
            android:layout_centerHorizontal="true"
            android:textColor="?android:textColorPrimary"
        />
    </RelativeLayout>

    <LinearLayout
        android:id="@+id/button_bar_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alwaysShow="true"
        android:orientation="vertical"
        android:background="?attr/colorBackground"
        android:layout_ignoreOffset="true">
        <View
            android:id="@+id/resolver_button_bar_divider"
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="?attr/colorBackground"
            android:foreground="?attr/dividerVertical" />
        <RelativeLayout
            style="?attr/buttonBarStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_ignoreOffset="true"
            android:layout_hasNestedScrollIndicator="true"
            android:gravity="end|center_vertical"
            android:orientation="horizontal"
            android:layoutDirection="locale"
            android:measureWithLargestChild="true"
            android:paddingTop="@dimen/resolver_button_bar_spacing"
            android:paddingBottom="@dimen/resolver_button_bar_spacing"
            android:paddingStart="@dimen/resolver_edge_margin"
            android:paddingEnd="@dimen/resolver_small_margin"
            android:elevation="@dimen/resolver_elevation">

            <Button
                android:id="@+id/use_same_profile_browser"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentStart="true"
                android:maxLines="2"
                style="@android:style/Widget.DeviceDefault.Button.Borderless"
                android:fontFamily="@android:string/config_headlineFontFamilyMedium"
                android:textAllCaps="false"
                android:text="@string/activity_resolver_use_once"
            />

            <Button
                android:id="@+id/button_open"
                android:layout_width="wrap_content"
                android:layout_alignParentEnd="true"
                android:maxLines="2"
                style="@android:style/Widget.DeviceDefault.Button.Colored"
                android:fontFamily="@android:string/config_headlineFontFamilyMedium"
                android:textAllCaps="false"
                android:layout_height="wrap_content"
                android:text="@string/whichViewApplicationLabel"
            />
        </RelativeLayout>
    </LinearLayout>
</com.android.internal.widget.ResolverDrawerLayout>
+2 −2
Original line number Diff line number Diff line
@@ -5936,9 +5936,9 @@
    <string name="resolver_no_personal_apps_available">No personal apps</string>

    <!-- Dialog title. User must choose between opening content in a cross-profile app or same-profile browser. [CHAR LIMIT=NONE] -->
    <string name="miniresolver_open_in_personal">Open in <xliff:g id="app" example="YouTube">%s</xliff:g> in personal profile?</string>
    <string name="miniresolver_open_in_personal">Open <xliff:g id="app" example="YouTube">%s</xliff:g> in your personal profile?</string>
    <!-- Dialog title. User must choose between opening content in a cross-profile app or same-profile browser. [CHAR LIMIT=NONE] -->
    <string name="miniresolver_open_in_work">Open in <xliff:g id="app" example="YouTube">%s</xliff:g> in work profile?</string>
    <string name="miniresolver_open_in_work">Open <xliff:g id="app" example="YouTube">%s</xliff:g> in your work profile?</string>
    <!-- Button option. Open the link in the personal browser. [CHAR LIMIT=NONE] -->
    <string name="miniresolver_use_personal_browser">Use personal browser</string>
    <!-- Button option. Open the link in the work browser. [CHAR LIMIT=NONE] -->
+8 −0
Original line number Diff line number Diff line
@@ -1599,6 +1599,13 @@
  <java-symbol type="layout" name="resolver_list_per_profile" />
  <java-symbol type="layout" name="chooser_list_per_profile" />
  <java-symbol type="layout" name="resolver_empty_states" />
  <java-symbol type="id" name="open_cross_profile" />
  <java-symbol type="string" name="miniresolver_open_in_personal" />
  <java-symbol type="string" name="miniresolver_open_in_work" />
  <java-symbol type="string" name="miniresolver_use_personal_browser" />
  <java-symbol type="string" name="miniresolver_use_work_browser" />
  <java-symbol type="id" name="button_open" />
  <java-symbol type="id" name="use_same_profile_browser" />

  <java-symbol type="anim" name="slide_in_child_bottom" />
  <java-symbol type="anim" name="slide_in_right" />
@@ -2715,6 +2722,7 @@
  <java-symbol type="bool" name="config_allow_ussd_over_ims" />
  <java-symbol type="attr" name="touchscreenBlocksFocus" />
  <java-symbol type="layout" name="resolver_list_with_default" />
  <java-symbol type="layout" name="miniresolver" />
  <java-symbol type="string" name="activity_resolver_use_always" />
  <java-symbol type="string" name="whichApplicationNamed" />
  <java-symbol type="string" name="whichApplicationLabel" />
+19 −0
Original line number Diff line number Diff line
@@ -730,6 +730,25 @@ public class ResolverActivityTest {
                .check(matches(isDisplayed()));
    }

    @Test
    public void testMiniResolver() {
        ResolverActivity.ENABLE_TABBED_VIEW = true;
        markWorkProfileUserAvailable();
        List<ResolvedComponentInfo> personalResolvedComponentInfos =
                createResolvedComponentsForTest(1);
        List<ResolvedComponentInfo> workResolvedComponentInfos =
                createResolvedComponentsForTest(1);
        // Personal profile only has a browser
        personalResolvedComponentInfos.get(0).getResolveInfoAt(0).handleAllWebDataURI = true;
        setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
        Intent sendIntent = createSendImageIntent();
        sendIntent.setType("TestType");

        mActivityRule.launchActivity(sendIntent);
        waitForIdle();
        onView(withId(R.id.open_cross_profile)).check(matches(isDisplayed()));
    }

    @Test
    public void testWorkTab_noAppsAvailable_workOff_noAppsAvailableEmptyStateShown() {
        // enable the work tab feature flag