feat: Foldable support

This commit is contained in:
Pun Butrach
2025-11-23 00:34:02 +07:00
parent 02f089a691
commit 19eb97e405
3 changed files with 38 additions and 20 deletions
+1
View File
@@ -21,6 +21,7 @@ This is a developer-focused change log:
* Big word that means Lawnchair will take system default hint bright/dark theme and fallback to luminosity detection for bright/dark mode detection in At a Glance.
* Variable font for Launcher3 (????????)
* Dynamically get app widget popup icon
* Foldable support (for real)
### 🥞 Snapshot 9 (Development 4 Release 1)
@@ -34,22 +34,28 @@ class LawnchairWindowManagerProxy @Inject constructor() : WindowManagerProxy(Uti
val TAG = "LC-WindowManagerProxy"
override fun estimateInternalDisplayBounds(displayInfoContext: Context): ArrayMap<CachedDisplayInfo, List<WindowBounds>> {
// Lawnchair-TODO(Foldable): See estimateInternalDisplayBounds in [SystemWindowManagerProxy]
// Wait... If SWMP fallback to getMaximumWindowMetrics from [WindowManager] public APIs
// That means that we can combine getMaximumWindowMetrics with getCurrentWindowMetrics!
// Wait... but doesn't that only account for two screens? What if there were more than two
// Until then *this* is a good enough solutions
// Wait... Launcher calls eIDB every time you interact, what happened if you switched screen
// to the screen with maximum window metrics screen? won't that cause duplicate with
// getCurrentWindowMetrics?
//
// True... we duplicate it, and cache it? Is there a better way to do this?
// We can't just call [getPossibleMaximumWindowMetrics] because it's an internal apis,
// reflection won't work. Thanks @SystemApi
val info = getDisplayInfo(displayInfoContext).normalize(this)
val bounds = estimateWindowBounds(displayInfoContext, info)
val result = ArrayMap<CachedDisplayInfo, List<WindowBounds>>().apply { put(info, bounds) }
Log.d(TAG, "estimateInternalDisplayBounds: $result")
val result = ArrayMap<CachedDisplayInfo, List<WindowBounds>>()
val displayManager = displayInfoContext.getSystemService(DisplayManager::class.java) ?: return result
val displays = displayManager.displays
for (display in displays) {
try {
val contextForDisplay = displayInfoContext.createDisplayContext(display)
val wm = contextForDisplay.getSystemService(WindowManager::class.java)
val metrics = if (Utilities.ATLEAST_R) wm.maximumWindowMetrics else null
if (metrics != null) {
val info = getDisplayInfo(metrics, display.rotation).normalize(this)
val bounds = estimateWindowBounds(contextForDisplay, info)
result[info] = bounds
}
} catch (e: Exception) {
Log.e(TAG, "Error estimating bounds for display ${display.displayId}", e)
}
}
return result
}
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.util;
import static android.content.pm.PackageManager.FEATURE_SENSOR_HINGE_ANGLE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -547,6 +548,8 @@ public class DisplayController implements DesktopVisibilityListener {
private final boolean mIsNightModeActive;
private boolean mIsFoldable;
public Info(Context displayInfoContext) {
/* don't need system overrides for external displays */
this(displayInfoContext, enableScalabilityForDesktopExperience()
@@ -575,6 +578,10 @@ public class DisplayController implements DesktopVisibilityListener {
mScreenSizeDp = new PortraitSize(config.screenHeightDp, config.screenWidthDp);
navigationMode = wmProxy.getNavigationMode(displayInfoContext);
mIsNightModeActive = config.isNightModeActive();
// LC: Hacky stuff but it work!
mIsFoldable = Utilities.ATLEAST_R && displayInfoContext.getPackageManager()
.hasSystemFeature(FEATURE_SENSOR_HINGE_ANGLE);
mPerDisplayBounds.putAll(perDisplayBoundsCache);
List<WindowBounds> cachedValue = getCurrentBounds();
@@ -726,12 +733,16 @@ public class DisplayController implements DesktopVisibilityListener {
.mapToInt(bounds -> isTablet(bounds) ? flagTablet : flagPhone)
.reduce(0, (a, b) -> a | b);
//type = flagTablet;
// pE-TODO(n/a): Testing DC!
if (type == (flagPhone | flagTablet)) {
Log.d("LC-DisplayController", "Device has multiple display (Phone|Tablet)");
Log.d("LC-DisplayController", "Device has multiple display (Phone|Tablet) based on bounds");
return TYPE_MULTI_DISPLAY;
} else if (type == flagTablet) {
}
if (type == flagTablet) {
// LC: Hacky stuff but it work!
if (mIsFoldable) {
Log.d("LC-DisplayController", "Device is Foldable (Tablet && Hinge Detected)");
return TYPE_MULTI_DISPLAY;
}
Log.d("LC-DisplayController", "Device has tablet profile (Tablet)");
return TYPE_TABLET;
} else {