From cb8b206a507c130031c97bd0b16e6c7ea35f084b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berke=20Emin=20Kabag=C3=B6z?= <47814461+berkekbgz@users.noreply.github.com> Date: Sun, 28 Sep 2025 04:21:02 +0300 Subject: [PATCH] Fix android 14 crashes (#5620) --- .../android/quickstep/RemoteTargetGluer.java | 3 +- .../com/android/quickstep/SystemUiProxy.java | 12 +++++- .../android/quickstep/views/RecentsView.java | 7 +++- .../launcher3/model/WorkspaceItemProcessor.kt | 2 +- .../shared/system/ActivityManagerWrapper.java | 19 +++++++++- .../system/InputConsumerController.java | 37 ++++++++++++++++++- .../RecentsAnimationControllerCompat.java | 22 ++++++++++- .../wm/shell/shared/DesktopModeStatus.java | 4 +- 8 files changed, 97 insertions(+), 9 deletions(-) diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java index a9da63f480..7cb1ab400f 100644 --- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java +++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java @@ -144,7 +144,8 @@ public class RemoteTargetGluer { // a) mSplitBounds was already set (from the clicked GroupedTaskView) // b) A SplitBounds was passed up from shell (via AbsSwipeUpHandler) // If both of these are null, we are in a 1-app or 1-app-plus-assistant case. - if (mSplitBounds == null) { + if (mSplitBounds == null && targets.extras != null + && targets.extras.containsKey(KEY_EXTRA_SPLIT_BOUNDS)) { SplitBounds shellSplitBounds = targets.extras.getParcelable(KEY_EXTRA_SPLIT_BOUNDS, SplitBounds.class); mSplitBounds = convertShellSplitBoundsToLauncher(shellSplitBounds); diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index 3d8426fb34..edbdda29c6 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -1569,6 +1569,16 @@ public class SystemUiProxy implements ISystemUiProxy, NavHandle, SafeCloseable { listener.onAnimationStart(new RecentsAnimationControllerCompat(controller), apps, wallpapers, homeContentInsets, minimizedHomeBounds, extras); } + + // Support for Android 13 and below + public void onAnimationStart(IRecentsAnimationController controller, + RemoteAnimationTarget[] apps, RemoteAnimationTarget[] nonAppTargets, + Rect homeContentInsets, Rect minimizedHomeBounds) { + // Chain the call to the newer 6-argument version, passing null for the 'extras' bundle. + onAnimationStart(controller, apps, nonAppTargets, homeContentInsets, + minimizedHomeBounds, null); + } + @Override public void onAnimationCanceled(int[] taskIds, TaskSnapshot[] taskSnapshots) { @@ -1642,4 +1652,4 @@ public class SystemUiProxy implements ISystemUiProxy, NavHandle, SafeCloseable { pw.println("\tmUnfoldAnimationListener=" + mUnfoldAnimationListener); pw.println("\tmDragAndDrop=" + mDragAndDrop); } -} \ No newline at end of file +} diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 23f2daf784..163732ff07 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -2883,7 +2883,12 @@ public abstract class RecentsView= Build.VERSION_CODES.P + && Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) { + hookDestroyInputConsumer(mWindowManager); + } else { + mWindowManager.destroyInputConsumer(mToken, DEFAULT_DISPLAY); + } + mWindowManager.createInputConsumer(mToken, mName, DEFAULT_DISPLAY, inputChannel); } catch (RemoteException e) { Log.e(TAG, "Failed to create input consumer", e); @@ -152,13 +162,36 @@ public class InputConsumerController { } } + + /** + * IWindowManager @destroyInputConsumer reflection + */ + private void hookDestroyInputConsumer(IWindowManager mWindowManager) throws RemoteException { + try { + Class iWindowManagerClass = Class.forName("android.view.IWindowManager"); + Method destroyInputConsumerMethod = iWindowManagerClass.getMethod("destroyInputConsumer", String.class, int.class); + destroyInputConsumerMethod.invoke(mWindowManager, mName, DEFAULT_DISPLAY); + } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | + InvocationTargetException e) { + Log.e(TAG, "Failed to invoke destroyInputConsumer", e); + mWindowManager.destroyInputConsumer(mToken, DEFAULT_DISPLAY); + } + + } + /** * Unregisters the input consumer. */ public void unregisterInputConsumer() { if (mInputEventReceiver != null) { try { - mWindowManager.destroyInputConsumer(mToken, DEFAULT_DISPLAY); + // Hook for Android P (9) to VANILLA_ICE_CREAM (15), where the method signature changed + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P + && Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) { + hookDestroyInputConsumer(mWindowManager); + } else { + mWindowManager.destroyInputConsumer(mToken, DEFAULT_DISPLAY); + } } catch (RemoteException e) { Log.e(TAG, "Failed to destroy input consumer", e); } diff --git a/systemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/systemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java index bbf4698420..be2a250dd8 100644 --- a/systemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java +++ b/systemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java @@ -16,6 +16,7 @@ package com.android.systemui.shared.system; +import android.os.Build; import android.os.RemoteException; import android.util.Log; import android.view.IRecentsAnimationController; @@ -26,6 +27,8 @@ import android.window.TaskSnapshot; import com.android.internal.os.IResultReceiver; import com.android.systemui.shared.recents.model.ThumbnailData; +import java.lang.reflect.Method; + public class RecentsAnimationControllerCompat { private static final String TAG = RecentsAnimationControllerCompat.class.getSimpleName(); @@ -92,7 +95,24 @@ public class RecentsAnimationControllerCompat { */ public void finish(boolean toHome, boolean sendUserLeaveHint, IResultReceiver finishCb) { try { - mAnimationController.finish(toHome, sendUserLeaveHint, finishCb); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { + mAnimationController.finish(toHome, sendUserLeaveHint, finishCb); + } else { + try { + Method finishMethod = mAnimationController.getClass().getMethod( + "finish", boolean.class, boolean.class); + finishMethod.invoke(mAnimationController, toHome, sendUserLeaveHint); + + if (finishCb != null) { + finishCb.send(0, null); + } + } catch (Exception e) { + Log.e(TAG, "Failed to finish recents animation via reflection", e); + if (finishCb != null) { + finishCb.send(0, null); + } + } + } } catch (RemoteException e) { Log.e(TAG, "Failed to finish recents animation", e); try { diff --git a/wmshell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java b/wmshell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java index 4876f327a6..6351722c15 100644 --- a/wmshell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java +++ b/wmshell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java @@ -19,6 +19,7 @@ package com.android.wm.shell.shared; import android.annotation.NonNull; import android.content.Context; import android.os.SystemProperties; +import android.os.Build; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; @@ -150,7 +151,8 @@ public class DesktopModeStatus { */ @VisibleForTesting public static boolean isDesktopModeSupported(@NonNull Context context) { - return context.getResources().getBoolean(R.bool.config_isDesktopModeSupported); + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM + && context.getResources().getBoolean(R.bool.config_isDesktopModeSupported); } /**