87844 Commits
Author SHA1 Message Date
Pun Butrach e53dcc5c42 fix: (DON'T MAKE) Folder reset scrim during allapps 2026-10-26 01:54:08 +07:00
Pun Butrach 9f1ed85224 fix: Adapt BaseDepthControllerImpl and folder spring animation properties 2026-10-26 00:49:09 +07:00
Pun Butrach 586cb6d5ba refactor: Adapt Lawnchair Shape function to PathWrapper 2026-10-26 00:15:33 +07:00
Tracy Zhou 2efdc9b814 Introduce PathWrapper that also tracks bounds and radii
So that we can use the bounds to set on BackgroundBlurDrawable

Bug: 445467156
Test: manual in the next CL
Flag: EXEMPT BUGFIX
Change-Id: I002d9dfd1d1aabc90c5cd6097772103575d91de9
2026-10-26 00:15:03 +07:00
Charlie Anderson c754a217b9 Fix folder view sticking during close anim when transitioning launcher page and/or state
Bug: 470662985
Test: manual
Flag: EXEMPT BUGFIX
Change-Id: I7a4841ad49cbc0339f6905869a1bb092e7f0c094
2026-10-26 00:12:20 +07:00
Charlie Anderson d66ece9a9c Fix folder clip reveal for multiple different issues
- Folder pages should not swipe out of bounds while opening
- Folder pages should be revealed if swiped in bounds while opening
- Closing the folder should not clip the preview icons

Bug: 458072199
Test: opening/closing/swiping a large folder
Flag: com.android.launcher3.enable_expressive_folder_expansion
Change-Id: I3773a9c79ec0e5efc24c0ac185a516353f955cec
2026-10-26 00:11:05 +07:00
Charlie Anderson 43940b201a Fix clip reveal so that folder doesn't scroll out of bounds while opening
Bug: 449923444
Flag: com.android.launcher3.enable_expressive_folder_expansion
Test: open folder and immediately swipe to next page

Change-Id: Iafa46f3748fdf0c1982b5de6df539b8c8609204f
2026-10-26 00:10:08 +07:00
Charlie Anderson 50cab79984 Fix folder animation workspace scaling to not conflict with other animations.
Bug: 456164513
Test: manual - close app and quickly open folder
Flag: com.android.launcher3.enable_expressive_folder_expansion

Change-Id: I47886b034402549176f99618699ae90bd0356086
2026-10-26 00:10:00 +07:00
Charlie Anderson e9c655dbf6 Add functionality to DepthController to control wallpaper zoom indepedently of blur
Also add wallpaper zoom to folder motion

Bug: b/387543793
Flag: com.android.launcher3.enable_expressive_folder_expansion
Test: manually and DepthControllerTest
Change-Id: I94142806ffb6dfb93d363017ef4d13b3a5e74681
2026-10-26 00:08:46 +07:00
Charlie Anderson 0d40f78616 Reset scrim and launcher workspace properties if folder is closed without animation
Bug: 452119282
Flag: com.android.launcher3.enable_expressive_folder_expansion
Test: use longpress on folder item and tap remove shortcut

Change-Id: Ia6e60189a74d731ed7a23ab74c144a228118a1d9
2026-10-26 00:03:41 +07:00
Charlie Anderson ea06691a37 Convert BubbleTextView Alpha to use spring animation
Flag: com.android.launcher3.enable_expressive_folder_expansion
Bug: 387543793
Test: Manually verifying


Change-Id: Ibadedb1fef2542a4b8373ab3a4557c10c8752a77
2026-10-26 00:00:31 +07:00
Lawnchair BotandCrowdin Bot 8be1c0f469 New Crowdin translations by GitHub Action (#7438)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2026-10-25 03:57:47 +03:30
def 793ac98db2 feat(feed): add Whisper to the feed provider whitelist (#7399) 2026-10-25 01:18:32 +08:00
renovate[bot] 60f90d713e fix(deps): update dependency net.bytebuddy:byte-buddy to v1.18.16-jdk5 (#7432)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-23 18:42:32 +00:00
renovate[bot] 745891d769 fix(deps): update dependency net.bytebuddy:byte-buddy-agent to v1.18.16-jdk5 (#7433)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-23 16:18:33 +00:00
caizhixingandcaizhixing 687153c642 fix: crash when dragging a folder on API 26-27 (#7428)
Bitmap.createBitmap(Picture) was only added in API 28, but Lawnchair
runs down to minSdk 26. Creating a folder drag preview on Android 8.x
therefore throws NoSuchMethodError and crashes the launcher.

Reuse the existing BitmapRenderer fallback on versions below P to
rasterize the recorded foreground Picture into a software bitmap.

Co-authored-by: caizhixing <17589399+caizhixing03@user.noreply.gitee.com>
2026-10-23 15:52:44 +07:00
renovate[bot] ab2d3621c9 fix(deps): update dependency com.google.errorprone:error_prone_annotations to v2.51.0 (#7429)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-22 11:56:48 +00:00
renovate[bot] c13364593e fix(deps): update dependency com.squareup.okhttp3:okhttp to v5.5.1 (#7425)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-22 04:55:15 +00:00
renovate[bot] c7e6b8dd75 fix(deps): update dependency androidx.palette:palette-ktx to v1.1.0 (#7422)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-21 23:05:02 +00:00
renovate[bot] fc5503ec25 fix(deps): update dependency androidx.datastore:datastore-preferences to v1.3.0 (#7421)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-21 20:38:41 +00:00
renovate[bot] e482061b22 fix(deps): update dependency androidx.compose.material3:material3 to v1.5.0-beta02 (#7420)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-21 20:37:57 +00:00
Pun Butrach eba9492be1 Revert "feat(home): live glass blur behind icons, folders and widgets (#7393)" (#7419)
This reverts commit d9afe890a3.
2026-10-21 22:19:44 +07:00
x-JOCandClaude Opus 5.5 d04b3b1c8d fix(prefs): reload the grid with the value just set (#7404)
* fix(prefs): reload the grid with the value just set

Most grid preferences reload the grid in their onSet. onSet runs right
after the DataStore write, but the device profiles read the preferences
through PreferenceManager2's cache (firstCached), which is updated by its
own collector on the main thread. That collector may not have run yet
when the reload runs inline, so the grid could be rebuilt from the
previous value: the change shows up only on the next reload, for example
after the next change of any grid preference.

ReloadHelper.reloadGrid now refreshes the cache from the DataStore, which
already has the new value, before reloading the grid. This fixes every
preference whose onSet calls reloadGrid, and the other callers
(restart(), the folder settings), with no change at the call sites. The
reload now always runs on the main thread, through PreferenceManager2's
Main.immediate scope.

Co-Authored-By: Claude <noreply@anthropic.com>
(cherry picked from commit cbe549ade0bac9d655a965ed8f802c8c19573ef5)

* fix(prefs): keep a newer cached value when the fresh read finishes late

With two quick grid changes, the first refresh could finish after the
collector had already stored the second value and put the older snapshot
back. Store the read result only if the cache hasn't changed meanwhile.

Suggested in review by CodeRabbit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-21 19:44:10 +08:00
x-JOCandClaude Opus 5.5 6c2c2c22ef fix(workspace): rework infinite scrolling without wrap state (#7413)
Infinite scrolling kept a wrap state (target page, saved scroll bounds,
a cached feed flag) that every path out of a swipe had to tear down.
Paths that missed it caused the bugs: a short or backward swipe on the
last page wrapped anyway, the first page flashed when a layout pass
reset the bounds mid-wrap, touching during a wrap jumped to the target,
two-panel layouts got stuck between pages, and the page indicator lost
its active dot.

The wrap now follows from the scroll position alone: on an end that
wraps, the scroll may run one screen further, and the screen from the
other end is translated into that gap. Workspace decides which ends
wrap; other paged views behave as in AOSP.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 19:41:57 +08:00
R05P0 d9afe890a3 feat(home): live glass blur behind icons, folders and widgets (#7393)
* feat(home): live glass blur behind icons, folders and widgets

Add an optional "Glass blur" setting that blurs the wallpaper behind home
screen icons, folder icons, open folders and widgets, like CSS
backdrop-filter. SurfaceFlinger renders the blur through blur regions
(a copy of the framework BackgroundBlurDrawable), so it stays live and
follows the items during page scrolls and animations.

SurfaceFlinger ignores all the blur of an app layer once there are more
than 10 blur requests on screen (kMaxBlurRequests, b/399120953), unless
the layer was created by a privileged process. With root, the regions go
to an effect layer created by the root helper and placed below the
launcher window content. Without root, they go to the window layer and
are subject to that limit.

Also fix RootHelperManager, unused until now: it reported root as not
available until a root shell had been created, and bound the root
service off the main thread.

* fix(home): redraw when a glass blur region is removed

Without a frame the pre-draw listener never sends the regions left, so a
removed blur, the last one in particular, could stay on screen until the
next redraw.
2026-10-21 19:34:15 +08:00
x-JOCandClaude Opus 5.5 3974765ea9 fix(drawer): update the search bar padding when the device profile changes (#7405)
AllAppsSearchInput sets its horizontal padding from the device profile
only when it is inflated and when the IDP changes. A DeviceProfile change
without an IDP change (rotation, or folding and unfolding once the
device type is stable) left the padding of the old profile. When it did
run, setupPadding() also reset the full padding even while a search was
active, where the bar uses half of it, and the focus and text listeners
kept animating to the paddings captured at inflation.

- Listen to DeviceProfile changes and update the padding then too.
- Keep the half padding while the search box is focused or holds a
  query, and cancel a running padding animation first.
- Animate to the current paddings rather than the inflation ones.

The search text and results are untouched. The result views already
follow the new profile: ActivityAllAppsContainerView#onDeviceProfileChanged
swaps the adapters and clears the view pool of every list, the search
list included, so all result views are inflated again with it.


(cherry picked from commit 090ce597ed7f6e35ee7fecb8235ea52d7be155c7)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 17:12:00 +08:00
x-JOCandClaude 59b60098b2 fix(grid): apply the icon size setting on responsive grids (#7407)
Home screen > Icon size (homeIconSizeFactor) had no effect on responsive
grids such as "practical": DeviceProfileOverrides scales the IDP's
iconSize, but responsive grids take their icon size from their cell
specs (mResponsiveWorkspaceCellSpec.getIconSize()) and never read
inv.iconSize.

getResponsiveIconSizePx() now applies the factor to the cell specs' icon
size, for the workspace, the hotseat and folder content, the same three
places the IDP-sized grids use inv.iconSize. The responsive code still
shrinks an icon that doesn't fit its cell (getIconSmallerThan). The icon
bitmap size already followed the factor, as the IDP computes it from the
scaled iconSize.

Visible change: on responsive grids the setting now works; at 100% (the
default) nothing changes.


(cherry picked from commit 6345b71df7dbd77be6c4da03ddcc76ebcadd2e90)

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-21 17:10:33 +08:00
x-JOCandClaude 5c1979227e fix(fold): keep the device type stable across folds (#7402)
* fix(display): keep the device type stable across folds

LawnchairWindowManagerProxy estimated the supported bounds only from
DisplayManager#getDisplays, which reports the panel in use. On a foldable
the DisplayController cache then held a single state, so every fold and
unfold invalidated it ("Unexpected normalizedDisplayInfo found"), the
device type flipped between PHONE (folded) and MULTI_DISPLAY (unfolded,
through the hinge check), and CHANGE_SUPPORTED_BOUNDS reloaded the grid
and the model. The smaller dock of the phone profile also made the
loader delete the dock items past its size.

On devices with FEATURE_SENSOR_HINGE_ANGLE, the estimate now also holds
the other states of the internal display:
- WindowManager#getPossibleMaximumWindowMetrics, like
  SystemWindowManagerProxy, when the system answers (it only does for the
  recents provider) and the current state is one of its states.
- Otherwise each state of the default display seen on the device is
  remembered. A state with the same aspect ratio replaces an older one,
  so a resolution change leaves no stale bounds.

The extra states are built the way DisplayController.Info builds the key
it looks up (getDisplayInfo(context).normalize(), no-cutout default), so
the lookup finds them and folding no longer changes the supported
bounds. Once both panels are known they hold a phone and a tablet size,
and the device type is MULTI_DISPLAY in both states, across restarts too.
A hinge device never seen unfolded still reports PHONE: flip phones also
have the hinge sensor, so it can't be assumed.

The states are kept in their own device-protected file,
lc_display_states, not in boot_aware_prefs: DisplayController can run
before unlock, the values must not be backed up or restored on another
device, and the write happens while DisplayController is being
constructed. AOSP's taskbar-pinning listener on boot_aware_prefs calls
getInfo() for every change, which is still null at that point, so a write
to that file crashed the launcher when it started on the other screen
than last time.

The hinge check now lives in one place, LawnchairWindowManagerProxy
.isFoldable(), which DisplayController.Info uses as well.

Co-Authored-By: Claude <noreply@anthropic.com>
(cherry picked from commit 14e6051ac83cba92cb371eec1c408966cb41ba9d)

* chore(display): log the device type once per info

getDeviceType() is called many times for each display change (once per
DeviceProfile and more), and logged its result every time. Log it once
per DisplayController.Info, that is once per display change, with the
current size, so the device type of each state can be read in logcat.

Co-Authored-By: Claude <noreply@anthropic.com>
(cherry picked from commit 9fa57ec7e3d678c3e19d6ce1309ae11b893e18fc)

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-21 17:09:10 +08:00
x-JOCandClaude Opus 5.5 20b34479c2 fix(fold): keep dock icons that don't fit the cover dock instead of deleting them (#7403)
* fix(fold): keep dock items past the hotseat size instead of deleting them

LoaderCursor#checkItemPlacement rejects hotseat items whose rank is not
below InvariantDeviceProfile#numDatabaseHotseatIcons, and checkAndAddItem
then marks them deleted like overlapping items, so they are removed from
the database. That size can shrink only for a while: on a foldable the
folded (phone) profile has a smaller hotseat than the unfolded one, and
folding once deleted the dock icons at ranks 4 and 5 for good.

Skip such items for binding but keep them in the database, so they show
up again once the hotseat is large enough. Why this is safe:
- Overlapping items (in bounds) are still deleted as before.
- Nothing can be placed at a rank past the current hotseat size, so a
  kept item can't collide with a new one while it is hidden. If it ever
  does, the regular overlap check deletes it when it comes back.
- Grid migrations are unchanged and run before the loader.
- Only top-level hotseat items are bound, so the contents of a kept
  folder stay unbound with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit d556864ee08d0e2494f21a5fc3a9f00676f1269a)

* fix(migration): skip dock entries past the hotseat size (pre-existing crash)

Both solveHotseatPlacement versions (GridSizeMigrationDBController and
GridSizeMigrationLogic) mark the target's remaining dock items in an
array sized to the new dock: occupied[entry.screenId] = true. When the
target grid's database was last used with a larger dock, an entry's
rank can be past that size, and moving back to that grid with anything
to add to the dock throws ArrayIndexOutOfBoundsException. The Kotlin
path then aborts the migration; the Java path resets the target
database.

Such an entry takes no slot in the new dock, so it is skipped when
marking. Nothing else changes: the placement loop and every other entry
are as before.

Co-Authored-By: Claude <noreply@anthropic.com>
(cherry picked from commit f9bdf9e9eebd710a11281c066c5293b76d71d18c)

* fix(migration): also skip negative dock ranks in the hotseat guard

A corrupt database could hold a negative hotseat rank, which would still
index outside the array. Such an entry takes no slot either.

Suggested in review by CodeRabbit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 17:07:28 +08:00
x-JOCandClaude Opus 5.5 99d015f121 fix(folder): keep the folder settings' defaults from the grid option (#7406)
InvariantDeviceProfile.initGrid took closestProfile's folder arrays as
they were, and DeviceProfileOverrides then wrote the folder settings
into them. The folder sliders take their default from closestProfile
(numFolderRows/numFolderColumns[INDEX_DEFAULT]), so the default they
compared against was the value currently applied, not the grid
option's. Setting the value that was already current, e.g. releasing
the slider thumb without moving it, removed the key and the folder grid
fell back to the grid option's on that reload.

Copy the arrays instead. Nothing else reads closestProfile's folder
arrays: the profiles read the IDP's own arrays, and every initGrid
parses fresh grid options.


(cherry picked from commit 198724e42446611b204d0700e6630a82d0c10502)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 17:06:00 +08:00
x-JOCandClaude Opus 5.5 d6f0bbcea9 fix(search): stop double-encoding web suggestion queries (#7389)
Retrofit already percent-encodes @Query parameters, so encoding the query with
Uri.encode first sent the literal "%D8%A7..." text to the suggestion APIs.
Non-ASCII queries (Arabic, Cyrillic, accented Latin, ...) got suggestions for
that escaped text, shown as hex bytes. Pass the raw query instead. The search
URLs built by hand in getSearchUrl still encode, as they should.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 16:58:07 +08:00
x-JOCandClaude Opus 5.5 75515f2c1b fix(i18n): plurals for relative times, two hardcoded strings (#7411)
* fix(about): count the changes' relative times as plurals

"5m", "3h" and the other relative times in the changes dialog were plain
strings, so languages that change the noun with the number, like
Arabic ("دقيقة", "دقيقتين", "5 دقائق"), had to pick one form that is
wrong for most numbers. Make them plurals; English stays the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(folders): translatable "Manage apps" in the drawer folder editor

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(settings): translatable empty pane text on large screens

The pane next to the settings menu on tablets and unfolded phones said
"Tap a preference in the left hand menu" in English only, and the menu
is on the right in right-to-left languages. Use a string that names no
side.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 16:44:15 +08:00
renovate[bot] e72e86b369 fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-serialization-json to v1.12.0 (#7417)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-20 18:16:30 +00:00
x-JOCandClaude Opus 5.5 ccdd15951a fix(drawer): two-line app labels in every language (#7410)
The "Use multiple lines" setting of the app drawer shows in every
language, but AOSP only honoured it in English, so it did nothing for
other languages. Labels break at spaces, or between words in camel case
names, which works for other scripts too.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 01:04:54 +07:00
renovate[bot] c9357e5ee3 chore(deps): update plugin com.gradle.develocity to v4.6.1 (#7416)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-20 16:38:55 +00:00
renovate[bot] eef747c4a6 chore(deps): update gradle to v9.8.2 (#7415)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-20 16:38:38 +00:00
TheSuperDragon fc100ae909 refactor: Improve icon system UX and consistency (#7397)
This commit improves Lawnchair's icon system by reorganizing the preference screens, while making icon behavior more deterministic in `LawnchairIconProvider` and cleaning up old and unused preferences.
2026-10-19 00:32:14 +08:00
Lawnchair BotandCrowdin Bot 6b426467a0 New Crowdin translations by GitHub Action (#7396)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2026-10-18 03:58:46 +03:30
Joseph Petersen 85335d904a fix(dock): remove unused label space when labels are hidden (#7364)
* fix(dock): remove unused label space when labels are hidden

* test(dock): remove tests and setup per review
2026-10-14 00:50:16 +08:00
Lawnchair BotandCrowdin Bot 62a50ddfa9 New Crowdin translations by GitHub Action (#7374)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2026-10-14 00:46:17 +08:00
renovate[bot] 398cafdc2d fix(deps): update dependency net.bytebuddy:byte-buddy to v1.18.15-jdk5 (#7383)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-13 16:42:28 +00:00
renovate[bot] cc99e5ae65 fix(deps): update dependency net.bytebuddy:byte-buddy-agent to v1.18.15-jdk5 (#7384)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-13 11:23:19 +00:00
Diego Pérez RuanovaandDiego Pérez Ruanova 7e082d84eb fix: let the paged dock keep mostly horizontal swipes (#7381)
VerticalSwipeTouchController uses BothAxesSwipeDetector, which has no angle
check. Once the touch drifts vertically by more than the touch slop it takes
over the stream and the dock pager receives ACTION_CANCEL, so a normal thumb
swipe (e.g. 450 px horizontal, 90 px vertical) leaves the dock half scrolled
or snaps back to the starting page.

When the touch starts on a paged dock, stop offering it to the vertical swipe
detector as soon as the motion is mostly horizontal (|dy| < 2 * |dx|).

- Closes: #7149

Co-authored-by: Diego Pérez Ruanova <25953869+dperezruanova@users.noreply.github.com>
2026-10-13 13:40:47 +08:00
renovate[bot] 23fdc1e239 fix(deps): update dependency io.nlopez.compose.rules:ktlint to v0.6.8 (#7380)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-12 15:47:08 +00:00
renovate[bot] 09be312ba5 fix(deps): update dependency androidx.compose.material3:material3 to v1.5.0-beta01 (#7379)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-12 11:10:15 +00:00
renovate[bot] 99fa2d16fb chore(deps): update plugin diffplug-spotless to v8.10.4 (#7378)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-12 11:09:03 +00:00
renovate[bot] 064b8811c0 chore(deps): update kotlin monorepo to v2.4.21 (#7377)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-12 07:51:26 +00:00
renovate[bot] 3135e483fd chore(deps): update gradle to v9.8.1 (#7376)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-12 07:50:57 +00:00
Pun Butrach 4793ba3a23 fix: Apply scaling to icon shape preview for consistency (#7369) 2026-10-06 22:04:37 +07:00
foXaCe e36078449f fix: Close file streams and write grid state after extraction (#7238) 2026-10-06 19:19:01 +07:00