From b0adb1d918f7cd2ec9ced2177929f7e3d8dd9540 Mon Sep 17 00:00:00 2001 From: Pavel Volkov Date: Mon, 13 Jul 2026 08:49:52 +0300 Subject: [PATCH] fix: Tighten app drawer spacing around search and tabs (#6991) Remove the double status-bar inset and leftover AOSP header padding so search, personal/work tabs, and the app grid sit at even gaps. Also collapse reserved space when the drawer search bar is hidden. --------- Co-authored-by: Cursor --- lawnchair/res/values/dimens.xml | 9 ++++ .../lawnchair/allapps/AllAppsSearchInput.kt | 27 +++++----- .../allapps/ActivityAllAppsContainerView.java | 52 +++++++++++++++---- 3 files changed, 65 insertions(+), 23 deletions(-) diff --git a/lawnchair/res/values/dimens.xml b/lawnchair/res/values/dimens.xml index 57294a7e6d..5f8094b701 100644 --- a/lawnchair/res/values/dimens.xml +++ b/lawnchair/res/values/dimens.xml @@ -67,7 +67,16 @@ 52dp 4dp + 64dp + + 4dp + 4dp + + 8dp + 4dp 1.5dp diff --git a/lawnchair/src/app/lawnchair/allapps/AllAppsSearchInput.kt b/lawnchair/src/app/lawnchair/allapps/AllAppsSearchInput.kt index fb69bbf6ed..06e67c1b51 100644 --- a/lawnchair/src/app/lawnchair/allapps/AllAppsSearchInput.kt +++ b/lawnchair/src/app/lawnchair/allapps/AllAppsSearchInput.kt @@ -24,6 +24,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.core.view.ViewCompat +import androidx.core.view.isGone import androidx.core.view.isInvisible import androidx.core.view.isVisible import androidx.core.widget.addTextChangedListener @@ -110,6 +111,7 @@ class AllAppsSearchInput(context: Context, attrs: AttributeSet?) : private var initialPaddingLeft: Int = 0 private var initialPaddingRight: Int = 0 + private var hideSearchBar = false override fun onFinishInflate() { super.onFinishInflate() @@ -271,9 +273,10 @@ class AllAppsSearchInput(context: Context, attrs: AttributeSet?) : }, ) - val hide = prefs2.hideAppDrawerSearchBar.firstCached() - if (hide) { - isInvisible = true + hideSearchBar = prefs2.hideAppDrawerSearchBar.firstCached() + if (hideSearchBar) { + // GONE so top margin/height do not reserve empty space above the app list. + isGone = true layoutParams.height = 0 } } @@ -440,20 +443,20 @@ class AllAppsSearchInput(context: Context, attrs: AttributeSet?) : override fun setInsets(insets: Rect) { (layoutParams as MarginLayoutParams).apply { - topMargin = if (isInvisible) { - insets.top - allAppsSearchVerticalOffset - } else { - max(-allAppsSearchVerticalOffset, insets.top - qsbMarginTopAdjusting) + topMargin = when { + hideSearchBar -> 0 + + // Sheet mode already pads the container with status-bar insets; only clear the + // drag handle. Re-applying insets.top here created the large empty band under it. + launcher.deviceProfile.shouldShowAllAppsOnSheet() -> + resources.getDimensionPixelSize(R.dimen.bottom_sheet_handle_area_height) + + else -> max(-allAppsSearchVerticalOffset, insets.top - qsbMarginTopAdjusting) } } requestLayout() } - override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { - super.onLayout(changed, l, t, r, b) - offsetTopAndBottom(allAppsSearchVerticalOffset) - } - override fun getEditText() = input override fun setBackgroundVisibility(visible: Boolean, maxAlpha: Float) { diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java index 17ac8e2dbf..d8166e8d82 100644 --- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java @@ -812,7 +812,10 @@ public class ActivityAllAppsContainerView removeCustomRules(rvContainer); removeCustomRules(getSearchRecyclerView()); - if (isSearchBarFloating()) { + if (isAppDrawerSearchBarHidden()) { + layoutWithoutSearchContainer(rvContainer, showTabs); + layoutWithoutSearchContainer(getSearchRecyclerView(), /* tabs= */ false); + } else if (isSearchBarFloating()) { alignParentTop(rvContainer, showTabs); alignParentTop(getSearchRecyclerView(), /* tabs= */ false); } else { @@ -826,8 +829,9 @@ public class ActivityAllAppsContainerView void setupHeader() { mAdditionalHeaderRows.forEach(row -> mHeader.onPluginDisconnected(row)); - var hideHeader = PreferenceCacheExtensionsKt.firstCached(pref2.getHideAppDrawerSearchBar()); - mHeader.setVisibility(hideHeader ? View.GONE : View.VISIBLE); + boolean hideSearchBar = isAppDrawerSearchBarHidden(); + // Keep personal/work tabs visible when search is off; only hide the empty header shell. + mHeader.setVisibility((hideSearchBar && !mUsingTabs) ? View.GONE : View.VISIBLE); boolean tabsHidden = !mUsingTabs; mHeader.setup( mAH.get(AdapterHolder.MAIN).mRecyclerView, @@ -836,7 +840,7 @@ public class ActivityAllAppsContainerView getCurrentPage(), tabsHidden); - int padding = mHeader.getMaxTranslation(); + int padding = (hideSearchBar && !mUsingTabs) ? 0 : mHeader.getMaxTranslation(); mAH.forEach(adapterHolder -> { adapterHolder.mPadding.top = padding; adapterHolder.applyPadding(); @@ -847,7 +851,9 @@ public class ActivityAllAppsContainerView mAdditionalHeaderRows.forEach(row -> mHeader.onPluginConnected(row, mActivityContext)); removeCustomRules(mHeader); - if (isSearchBarFloating()) { + if (hideSearchBar) { + layoutWithoutSearchContainer(mHeader, false /* includeTabsMargin */); + } else if (isSearchBarFloating()) { alignParentTop(mHeader, false /* includeTabsMargin */); } else { layoutBelowSearchContainer(mHeader, false /* includeTabsMargin */); @@ -879,7 +885,7 @@ public class ActivityAllAppsContainerView } protected void updateHeaderScroll(int scrolledOffset) { - if (PreferenceCacheExtensionsKt.firstCached(pref2.getHideAppDrawerSearchBar())) + if (isAppDrawerSearchBarHidden() && !mUsingTabs) return; // Check if tab container background should be shown @@ -1024,6 +1030,10 @@ public class ActivityAllAppsContainerView return dp.allAppsLeftRightMargin + dp.getAllAppsIconStartMargin(mActivityContext); } + private boolean isAppDrawerSearchBarHidden() { + return PreferenceCacheExtensionsKt.firstCached(pref2.getHideAppDrawerSearchBar()); + } + private void layoutBelowSearchContainer(View v, boolean includeTabsMargin) { if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) { return; @@ -1042,8 +1052,7 @@ public class ActivityAllAppsContainerView } private void alignParentTop(View v, boolean includeTabsMargin) { - if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams) - || PreferenceCacheExtensionsKt.firstCached(pref2.getHideAppDrawerSearchBar())) { + if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) { return; } @@ -1057,8 +1066,7 @@ public class ActivityAllAppsContainerView } private void removeCustomRules(View v) { - if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams) - || PreferenceCacheExtensionsKt.firstCached(pref2.getHideAppDrawerSearchBar())) { + if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) { return; } @@ -1068,6 +1076,26 @@ public class ActivityAllAppsContainerView layoutParams.removeRule(RelativeLayout.ALIGN_PARENT_TOP); } + private void layoutWithoutSearchContainer(View v, boolean includeTabsMargin) { + if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) { + return; + } + + RelativeLayout.LayoutParams layoutParams = (LayoutParams) v.getLayoutParams(); + layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP); + int topMargin = 0; + if (mActivityContext.getDeviceProfile().shouldShowAllAppsOnSheet()) { + // Clear the bottom-sheet drag handle when search is not reserving that space. + topMargin = getContext().getResources().getDimensionPixelSize( + R.dimen.bottom_sheet_handle_area_height); + } + if (includeTabsMargin) { + topMargin += getContext().getResources().getDimensionPixelSize( + R.dimen.all_apps_header_pill_height); + } + layoutParams.topMargin = topMargin; + } + protected BaseAllAppsAdapter createAdapter(AlphabeticalAppsList appsList) { return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), appsList, mMainAdapterProvider); @@ -1387,7 +1415,9 @@ public class ActivityAllAppsContainerView } else { getSearchRecyclerView().setVisibility(GONE); getAppsRecyclerViewContainer().setVisibility(VISIBLE); - mHeader.setVisibility(VISIBLE); + // Keep the empty header shell hidden when search is off and there are no tabs. + mHeader.setVisibility( + (isAppDrawerSearchBarHidden() && !mUsingTabs) ? View.GONE : View.VISIBLE); } if (mHeader.isSetUp()) { mHeader.setActiveRV(getCurrentPage());