Loading core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java +1 −1 Original line number Diff line number Diff line Loading @@ -54,7 +54,7 @@ public class AccessibilityButtonChooserActivity extends Activity { final ResolverDrawerLayout rdl = findViewById(R.id.contentPanel); if (rdl != null) { rdl.setOnDismissedListener(this::finish); rdl.setOnDismissListener(this::finish); } final AccessibilityManager accessibilityManager = Loading core/java/com/android/internal/app/ResolverActivity.java +47 −37 Original line number Diff line number Diff line Loading @@ -125,6 +125,7 @@ import com.android.internal.content.PackageMonitor; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.util.LatencyTracker; import com.android.internal.widget.DismissableView; import com.android.internal.widget.ResolverDrawerLayout; import com.android.internal.widget.ViewPager; Loading Loading @@ -169,6 +170,7 @@ public class ResolverActivity extends Activity implements private int mDefaultTitleResId; // Expected to be true if this object is ResolverActivity or is ResolverWrapperActivity. private final boolean mIsIntentPicker; private View mContainer; // Whether this activity was instantiated with a specialized constructor that predefines a list // of resolutions to be displayed for the target intent (as in, e.g., the NFC use case). Loading @@ -177,6 +179,8 @@ public class ResolverActivity extends Activity implements // Whether or not this activity supports choosing a default handler for the intent. @VisibleForTesting protected boolean mSupportsAlwaysUseOption; // TODO(b/417351080): mResolverDrawerLayout is only used in ChooserActivity. Usage should be // refactored to use mContainer. protected ResolverDrawerLayout mResolverDrawerLayout; @UnsupportedAppUsage protected PackageManager mPm; Loading Loading @@ -465,9 +469,10 @@ public class ResolverActivity extends Activity implements // We also turn it off when clonedProfile is present on the device, because we might have // different "last chosen" activities in the different profiles, and PackageManager doesn't // provide any more information to help us select between them. boolean filterLastUsed = mSupportsAlwaysUseOption && !isVoiceInteraction() && !shouldShowTabs() && !hasCloneProfile(); mMultiProfilePagerAdapter = createMultiProfilePagerAdapter(initialIntents, rList, filterLastUsed); boolean filterLastUsed = filterLastUsedConfig() && mSupportsAlwaysUseOption && !isVoiceInteraction() && !shouldShowTabs() && !hasCloneProfile(); mMultiProfilePagerAdapter = createMultiProfilePagerAdapter(initialIntents, rList, filterLastUsed); if (configureContentView()) { return; } Loading @@ -484,15 +489,19 @@ public class ResolverActivity extends Activity implements mRegistered = true; final ResolverDrawerLayout rdl = findViewById(R.id.contentPanel); if (rdl != null) { rdl.setOnDismissedListener(new ResolverDrawerLayout.OnDismissedListener() { @Override public void onDismissed() { finish(); mContainer = findViewById(R.id.contentPanel); if (mContainer != null) { // TODO(b/417351080): The flags and insets are the responsibility of the container // and should be moved to the container implementation. mContainer.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); mContainer.setOnApplyWindowInsetsListener(this::onApplyWindowInsets); if (mContainer instanceof DismissableView container) { container.setOnDismissListener(this::finish); } }); if (mContainer instanceof final ResolverDrawerLayout rdl) { boolean hasTouchScreen = getPackageManager() .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN); Loading @@ -500,10 +509,6 @@ public class ResolverActivity extends Activity implements rdl.setCollapsed(false); } rdl.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); rdl.setOnApplyWindowInsetsListener(this::onApplyWindowInsets); mResolverDrawerLayout = rdl; for (int i = 0, size = mMultiProfilePagerAdapter.getCount(); i < size; i++) { Loading @@ -514,6 +519,7 @@ public class ResolverActivity extends Activity implements } } } } mProfileView = findViewById(R.id.profile_button); if (mProfileView != null) { Loading @@ -529,6 +535,10 @@ public class ResolverActivity extends Activity implements + (categories != null ? Arrays.toString(categories.toArray()) : "")); } protected boolean filterLastUsedConfig() { return getResources().getBoolean(R.bool.config_resolverActivityFilterLastUsed); } protected AbstractMultiProfilePagerAdapter createMultiProfilePagerAdapter( Intent[] initialIntents, List<ResolveInfo> rList, Loading Loading @@ -922,8 +932,10 @@ public class ResolverActivity extends Activity implements protected WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { mSystemWindowInsets = insets.getSystemWindowInsets(); mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top, if (mContainer != null) { mContainer.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top, mSystemWindowInsets.right, 0); } resetButtonBar(); Loading Loading @@ -953,8 +965,8 @@ public class ResolverActivity extends Activity implements updateIntentPickerPaddings(); } if (mSystemWindowInsets != null) { mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top, if (mSystemWindowInsets != null && mContainer != null) { mContainer.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top, mSystemWindowInsets.right, 0); } } Loading Loading @@ -1430,8 +1442,7 @@ public class ResolverActivity extends Activity implements final ItemClickListener listener = new ItemClickListener(); setupAdapterListView((ListView) mMultiProfilePagerAdapter.getActiveAdapterView(), listener); if (shouldShowTabs() && mIsIntentPicker) { final ResolverDrawerLayout rdl = findViewById(R.id.contentPanel); if (rdl != null) { if (findViewById(R.id.contentPanel) instanceof ResolverDrawerLayout rdl) { rdl.setMaxCollapsedHeight(getResources() .getDimensionPixelSize(useLayoutWithDefault() ? R.dimen.resolver_max_collapsed_height_with_default_with_tabs Loading Loading @@ -2336,12 +2347,11 @@ public class ResolverActivity extends Activity implements * the screen. */ private void setButtonBarIgnoreOffset(boolean ignoreOffset) { View buttonBarContainer = findViewById(R.id.button_bar_container); if (buttonBarContainer != null) { ResolverDrawerLayout.LayoutParams layoutParams = (ResolverDrawerLayout.LayoutParams) buttonBarContainer.getLayoutParams(); layoutParams.ignoreOffset = ignoreOffset; buttonBarContainer.setLayoutParams(layoutParams); View container = findViewById(R.id.button_bar_container); if (container != null && container.getLayoutParams() instanceof ResolverDrawerLayout.LayoutParams lp) { lp.ignoreOffset = ignoreOffset; container.setLayoutParams(lp); } } Loading core/java/com/android/internal/widget/DismissableView.java 0 → 100644 +40 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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. */ package com.android.internal.widget; /** * Views that implement DismissableView allow the parent activity to listen for a dismiss event * (e.g. when the user clicks outside a bottom sheet container). */ public interface DismissableView { /** * Sets a dismiss callback. */ void setOnDismissListener(OnDismissListener listener); /** * Listener for view dismiss events. */ interface OnDismissListener { /** * Callback when the view is dismissed by the user. */ void onDismiss(); } } core/java/com/android/internal/widget/ResolverDrawerLayout.java +5 −14 Original line number Diff line number Diff line Loading @@ -50,7 +50,7 @@ import com.android.internal.R; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; public class ResolverDrawerLayout extends ViewGroup { public class ResolverDrawerLayout extends ViewGroup implements DismissableView { private static final String TAG = "ResolverDrawerLayout"; private MetricsLogger mMetricsLogger; Loading Loading @@ -117,7 +117,7 @@ public class ResolverDrawerLayout extends ViewGroup { private Drawable mScrollIndicatorDrawable; private OnDismissedListener mOnDismissedListener; private OnDismissListener mOnDismissedListener; private RunOnDismissedListener mRunOnDismissedListener; private OnCollapsedChangedListener mOnCollapsedChangedListener; Loading Loading @@ -311,7 +311,8 @@ public class ResolverDrawerLayout extends ViewGroup { + mCollapsibleHeightReserved; } public void setOnDismissedListener(OnDismissedListener listener) { @Override public void setOnDismissListener(OnDismissListener listener) { mOnDismissedListener = listener; } Loading Loading @@ -651,7 +652,7 @@ public class ResolverDrawerLayout extends ViewGroup { void dispatchOnDismissed() { if (mOnDismissedListener != null) { mOnDismissedListener.onDismissed(); mOnDismissedListener.onDismiss(); } if (mRunOnDismissedListener != null) { removeCallbacks(mRunOnDismissedListener); Loading Loading @@ -1258,16 +1259,6 @@ public class ResolverDrawerLayout extends ViewGroup { }; } /** * Listener for sheet dismissed events. */ public interface OnDismissedListener { /** * Callback when the sheet is dismissed by the user. */ void onDismissed(); } /** * Listener for sheet collapsed / expanded events. */ Loading core/res/res/values/config.xml +5 −0 Original line number Diff line number Diff line Loading @@ -7625,6 +7625,11 @@ <!-- Maximum number of devices that allows for audio sharing. --> <integer name="config_audio_sharing_maximum_sinks">2</integer> <!-- Whether ResolverActivity should highlight the last used app. When false, ResolverActivity shows a list of apps instead of highlighting the last used app and displaying other apps separately. --> <bool name="config_resolverActivityFilterLastUsed">true</bool> <!--For App Function, this configuration lists package names grouped as "Device Settings". Packages in this list share the same App Function access settings. In the UI, they are presented as a single "Device Settings" item rather than individually. --> Loading Loading
core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java +1 −1 Original line number Diff line number Diff line Loading @@ -54,7 +54,7 @@ public class AccessibilityButtonChooserActivity extends Activity { final ResolverDrawerLayout rdl = findViewById(R.id.contentPanel); if (rdl != null) { rdl.setOnDismissedListener(this::finish); rdl.setOnDismissListener(this::finish); } final AccessibilityManager accessibilityManager = Loading
core/java/com/android/internal/app/ResolverActivity.java +47 −37 Original line number Diff line number Diff line Loading @@ -125,6 +125,7 @@ import com.android.internal.content.PackageMonitor; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.util.LatencyTracker; import com.android.internal.widget.DismissableView; import com.android.internal.widget.ResolverDrawerLayout; import com.android.internal.widget.ViewPager; Loading Loading @@ -169,6 +170,7 @@ public class ResolverActivity extends Activity implements private int mDefaultTitleResId; // Expected to be true if this object is ResolverActivity or is ResolverWrapperActivity. private final boolean mIsIntentPicker; private View mContainer; // Whether this activity was instantiated with a specialized constructor that predefines a list // of resolutions to be displayed for the target intent (as in, e.g., the NFC use case). Loading @@ -177,6 +179,8 @@ public class ResolverActivity extends Activity implements // Whether or not this activity supports choosing a default handler for the intent. @VisibleForTesting protected boolean mSupportsAlwaysUseOption; // TODO(b/417351080): mResolverDrawerLayout is only used in ChooserActivity. Usage should be // refactored to use mContainer. protected ResolverDrawerLayout mResolverDrawerLayout; @UnsupportedAppUsage protected PackageManager mPm; Loading Loading @@ -465,9 +469,10 @@ public class ResolverActivity extends Activity implements // We also turn it off when clonedProfile is present on the device, because we might have // different "last chosen" activities in the different profiles, and PackageManager doesn't // provide any more information to help us select between them. boolean filterLastUsed = mSupportsAlwaysUseOption && !isVoiceInteraction() && !shouldShowTabs() && !hasCloneProfile(); mMultiProfilePagerAdapter = createMultiProfilePagerAdapter(initialIntents, rList, filterLastUsed); boolean filterLastUsed = filterLastUsedConfig() && mSupportsAlwaysUseOption && !isVoiceInteraction() && !shouldShowTabs() && !hasCloneProfile(); mMultiProfilePagerAdapter = createMultiProfilePagerAdapter(initialIntents, rList, filterLastUsed); if (configureContentView()) { return; } Loading @@ -484,15 +489,19 @@ public class ResolverActivity extends Activity implements mRegistered = true; final ResolverDrawerLayout rdl = findViewById(R.id.contentPanel); if (rdl != null) { rdl.setOnDismissedListener(new ResolverDrawerLayout.OnDismissedListener() { @Override public void onDismissed() { finish(); mContainer = findViewById(R.id.contentPanel); if (mContainer != null) { // TODO(b/417351080): The flags and insets are the responsibility of the container // and should be moved to the container implementation. mContainer.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); mContainer.setOnApplyWindowInsetsListener(this::onApplyWindowInsets); if (mContainer instanceof DismissableView container) { container.setOnDismissListener(this::finish); } }); if (mContainer instanceof final ResolverDrawerLayout rdl) { boolean hasTouchScreen = getPackageManager() .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN); Loading @@ -500,10 +509,6 @@ public class ResolverActivity extends Activity implements rdl.setCollapsed(false); } rdl.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); rdl.setOnApplyWindowInsetsListener(this::onApplyWindowInsets); mResolverDrawerLayout = rdl; for (int i = 0, size = mMultiProfilePagerAdapter.getCount(); i < size; i++) { Loading @@ -514,6 +519,7 @@ public class ResolverActivity extends Activity implements } } } } mProfileView = findViewById(R.id.profile_button); if (mProfileView != null) { Loading @@ -529,6 +535,10 @@ public class ResolverActivity extends Activity implements + (categories != null ? Arrays.toString(categories.toArray()) : "")); } protected boolean filterLastUsedConfig() { return getResources().getBoolean(R.bool.config_resolverActivityFilterLastUsed); } protected AbstractMultiProfilePagerAdapter createMultiProfilePagerAdapter( Intent[] initialIntents, List<ResolveInfo> rList, Loading Loading @@ -922,8 +932,10 @@ public class ResolverActivity extends Activity implements protected WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { mSystemWindowInsets = insets.getSystemWindowInsets(); mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top, if (mContainer != null) { mContainer.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top, mSystemWindowInsets.right, 0); } resetButtonBar(); Loading Loading @@ -953,8 +965,8 @@ public class ResolverActivity extends Activity implements updateIntentPickerPaddings(); } if (mSystemWindowInsets != null) { mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top, if (mSystemWindowInsets != null && mContainer != null) { mContainer.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top, mSystemWindowInsets.right, 0); } } Loading Loading @@ -1430,8 +1442,7 @@ public class ResolverActivity extends Activity implements final ItemClickListener listener = new ItemClickListener(); setupAdapterListView((ListView) mMultiProfilePagerAdapter.getActiveAdapterView(), listener); if (shouldShowTabs() && mIsIntentPicker) { final ResolverDrawerLayout rdl = findViewById(R.id.contentPanel); if (rdl != null) { if (findViewById(R.id.contentPanel) instanceof ResolverDrawerLayout rdl) { rdl.setMaxCollapsedHeight(getResources() .getDimensionPixelSize(useLayoutWithDefault() ? R.dimen.resolver_max_collapsed_height_with_default_with_tabs Loading Loading @@ -2336,12 +2347,11 @@ public class ResolverActivity extends Activity implements * the screen. */ private void setButtonBarIgnoreOffset(boolean ignoreOffset) { View buttonBarContainer = findViewById(R.id.button_bar_container); if (buttonBarContainer != null) { ResolverDrawerLayout.LayoutParams layoutParams = (ResolverDrawerLayout.LayoutParams) buttonBarContainer.getLayoutParams(); layoutParams.ignoreOffset = ignoreOffset; buttonBarContainer.setLayoutParams(layoutParams); View container = findViewById(R.id.button_bar_container); if (container != null && container.getLayoutParams() instanceof ResolverDrawerLayout.LayoutParams lp) { lp.ignoreOffset = ignoreOffset; container.setLayoutParams(lp); } } Loading
core/java/com/android/internal/widget/DismissableView.java 0 → 100644 +40 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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. */ package com.android.internal.widget; /** * Views that implement DismissableView allow the parent activity to listen for a dismiss event * (e.g. when the user clicks outside a bottom sheet container). */ public interface DismissableView { /** * Sets a dismiss callback. */ void setOnDismissListener(OnDismissListener listener); /** * Listener for view dismiss events. */ interface OnDismissListener { /** * Callback when the view is dismissed by the user. */ void onDismiss(); } }
core/java/com/android/internal/widget/ResolverDrawerLayout.java +5 −14 Original line number Diff line number Diff line Loading @@ -50,7 +50,7 @@ import com.android.internal.R; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; public class ResolverDrawerLayout extends ViewGroup { public class ResolverDrawerLayout extends ViewGroup implements DismissableView { private static final String TAG = "ResolverDrawerLayout"; private MetricsLogger mMetricsLogger; Loading Loading @@ -117,7 +117,7 @@ public class ResolverDrawerLayout extends ViewGroup { private Drawable mScrollIndicatorDrawable; private OnDismissedListener mOnDismissedListener; private OnDismissListener mOnDismissedListener; private RunOnDismissedListener mRunOnDismissedListener; private OnCollapsedChangedListener mOnCollapsedChangedListener; Loading Loading @@ -311,7 +311,8 @@ public class ResolverDrawerLayout extends ViewGroup { + mCollapsibleHeightReserved; } public void setOnDismissedListener(OnDismissedListener listener) { @Override public void setOnDismissListener(OnDismissListener listener) { mOnDismissedListener = listener; } Loading Loading @@ -651,7 +652,7 @@ public class ResolverDrawerLayout extends ViewGroup { void dispatchOnDismissed() { if (mOnDismissedListener != null) { mOnDismissedListener.onDismissed(); mOnDismissedListener.onDismiss(); } if (mRunOnDismissedListener != null) { removeCallbacks(mRunOnDismissedListener); Loading Loading @@ -1258,16 +1259,6 @@ public class ResolverDrawerLayout extends ViewGroup { }; } /** * Listener for sheet dismissed events. */ public interface OnDismissedListener { /** * Callback when the sheet is dismissed by the user. */ void onDismissed(); } /** * Listener for sheet collapsed / expanded events. */ Loading
core/res/res/values/config.xml +5 −0 Original line number Diff line number Diff line Loading @@ -7625,6 +7625,11 @@ <!-- Maximum number of devices that allows for audio sharing. --> <integer name="config_audio_sharing_maximum_sinks">2</integer> <!-- Whether ResolverActivity should highlight the last used app. When false, ResolverActivity shows a list of apps instead of highlighting the last used app and displaying other apps separately. --> <bool name="config_resolverActivityFilterLastUsed">true</bool> <!--For App Function, this configuration lists package names grouped as "Device Settings". Packages in this list share the same App Function access settings. In the UI, they are presented as a single "Device Settings" item rather than individually. --> Loading