Loading core/java/com/android/internal/app/ResolverActivity.java +77 −2 Original line number Diff line number Diff line Loading @@ -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(); } Loading Loading @@ -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 { Loading @@ -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. Loading core/res/res/layout/miniresolver.xml 0 → 100644 +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> core/res/res/values/strings.xml +2 −2 Original line number Diff line number Diff line Loading @@ -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] --> Loading core/res/res/values/symbols.xml +8 −0 Original line number Diff line number Diff line Loading @@ -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" /> Loading Loading @@ -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" /> Loading core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java +19 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading
core/java/com/android/internal/app/ResolverActivity.java +77 −2 Original line number Diff line number Diff line Loading @@ -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(); } Loading Loading @@ -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 { Loading @@ -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. Loading
core/res/res/layout/miniresolver.xml 0 → 100644 +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>
core/res/res/values/strings.xml +2 −2 Original line number Diff line number Diff line Loading @@ -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] --> Loading
core/res/res/values/symbols.xml +8 −0 Original line number Diff line number Diff line Loading @@ -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" /> Loading Loading @@ -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" /> Loading
core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java +19 −0 Original line number Diff line number Diff line Loading @@ -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 Loading