Loading libs/WindowManager/Shell/src/com/android/wm/shell/common/HomeIntentProvider.kt 0 → 100644 +65 −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.wm.shell.common import android.app.ActivityManager import android.app.ActivityOptions import android.app.PendingIntent import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.content.Context import android.content.Intent import android.os.UserHandle import android.view.Display.DEFAULT_DISPLAY import android.window.WindowContainerTransaction import com.android.window.flags.Flags /** Creates home intent **/ class HomeIntentProvider( private val context: Context, ) { fun addLaunchHomePendingIntent( wct: WindowContainerTransaction, displayId: Int, userId: Int? = null ) { val userHandle = if (userId != null) UserHandle.of(userId) else UserHandle.of(ActivityManager.getCurrentUser()) val launchHomeIntent = Intent(Intent.ACTION_MAIN).apply { if (displayId != DEFAULT_DISPLAY) { addCategory(Intent.CATEGORY_SECONDARY_HOME) } else { addCategory(Intent.CATEGORY_HOME) } } val options = ActivityOptions.makeBasic().apply { launchWindowingMode = WINDOWING_MODE_FULLSCREEN pendingIntentBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS if (Flags.enablePerDisplayDesktopWallpaperActivity()) { launchDisplayId = displayId } } val pendingIntent = PendingIntent.getActivityAsUser( context, /* requestCode= */ 0, launchHomeIntent, PendingIntent.FLAG_IMMUTABLE, /* options= */ null, userHandle, ) wct.sendPendingIntent(pendingIntent, launchHomeIntent, options.toBundle()) } } No newline at end of file libs/WindowManager/Shell/src/com/android/wm/shell/crashhandling/OWNERS 0 → 100644 +2 −0 Original line number Diff line number Diff line # WM shell sub-module crash handling owners uysalorhan@google.com No newline at end of file libs/WindowManager/Shell/src/com/android/wm/shell/crashhandling/ShellCrashHandler.kt 0 → 100644 +75 −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.wm.shell.crashhandling import android.app.WindowConfiguration import android.content.Context import android.view.Display.DEFAULT_DISPLAY import android.window.DesktopExperienceFlags import android.window.WindowContainerTransaction import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.common.HomeIntentProvider import com.android.wm.shell.shared.desktopmode.DesktopModeStatus import com.android.wm.shell.sysui.ShellInit /** [ShellCrashHandler] for shell to use when it's being initialized. Currently it only restores * the home task to top. **/ class ShellCrashHandler( private val context: Context, private val shellTaskOrganizer: ShellTaskOrganizer, private val homeIntentProvider: HomeIntentProvider, shellInit: ShellInit, ) { init { shellInit.addInitCallback(::onInit, this) } private fun onInit() { handleCrashIfNeeded() } private fun handleCrashIfNeeded() { // For now only handle crashes when desktop mode is enabled on the device. if (DesktopModeStatus.canEnterDesktopMode(context) && !DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { var freeformTaskExists = false // If there are running tasks at init, WMShell has crashed but WMCore is still alive. for (task in shellTaskOrganizer.getRunningTasks()) { if (task.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM) { freeformTaskExists = true } if (freeformTaskExists) { shellTaskOrganizer.applyTransaction( addLaunchHomePendingIntent(WindowContainerTransaction(), DEFAULT_DISPLAY) ) break } } } } private fun addLaunchHomePendingIntent( wct: WindowContainerTransaction, displayId: Int ): WindowContainerTransaction { // TODO: b/400462917 - Check that crashes are also handled correctly on HSUM devices. We // might need to pass the [userId] here to launch the correct home. homeIntentProvider.addLaunchHomePendingIntent(wct, displayId) return wct } } No newline at end of file libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +24 −3 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.FloatingContentCoordinator; import com.android.wm.shell.common.HomeIntentProvider; import com.android.wm.shell.common.LaunchAdjacentController; import com.android.wm.shell.common.MultiDisplayDragMoveIndicatorController; import com.android.wm.shell.common.MultiDisplayDragMoveIndicatorSurface; Loading @@ -80,6 +81,7 @@ import com.android.wm.shell.common.UserProfileContexts; import com.android.wm.shell.common.split.SplitState; import com.android.wm.shell.compatui.letterbox.LetterboxCommandHandler; import com.android.wm.shell.compatui.letterbox.LetterboxTransitionObserver; import com.android.wm.shell.crashhandling.ShellCrashHandler; import com.android.wm.shell.dagger.back.ShellBackAnimationModule; import com.android.wm.shell.dagger.pip.PipModule; import com.android.wm.shell.desktopmode.CloseDesktopTaskTransitionHandler; Loading Loading @@ -779,7 +781,8 @@ public abstract class WMShellModule { UserProfileContexts userProfileContexts, DesktopModeCompatPolicy desktopModeCompatPolicy, DragToDisplayTransitionHandler dragToDisplayTransitionHandler, DesktopModeMoveToDisplayTransitionHandler moveToDisplayTransitionHandler) { DesktopModeMoveToDisplayTransitionHandler moveToDisplayTransitionHandler, HomeIntentProvider homeIntentProvider) { return new DesktopTasksController( context, shellInit, Loading Loading @@ -820,7 +823,8 @@ public abstract class WMShellModule { userProfileContexts, desktopModeCompatPolicy, dragToDisplayTransitionHandler, moveToDisplayTransitionHandler); moveToDisplayTransitionHandler, homeIntentProvider); } @WMSingleton Loading Loading @@ -1544,7 +1548,8 @@ public abstract class WMShellModule { Optional<DesktopTasksTransitionObserver> desktopTasksTransitionObserverOptional, Optional<DesktopDisplayEventHandler> desktopDisplayEventHandler, Optional<DesktopModeKeyGestureHandler> desktopModeKeyGestureHandler, Optional<SystemModalsTransitionHandler> systemModalsTransitionHandler) { Optional<SystemModalsTransitionHandler> systemModalsTransitionHandler, ShellCrashHandler shellCrashHandler) { return new Object(); } Loading @@ -1564,4 +1569,20 @@ public abstract class WMShellModule { return new UserProfileContexts(context, shellController, shellInit); } @WMSingleton @Provides static ShellCrashHandler provideShellCrashHandler( Context context, ShellTaskOrganizer shellTaskOrganizer, HomeIntentProvider homeIntentProvider, ShellInit shellInit) { return new ShellCrashHandler(context, shellTaskOrganizer, homeIntentProvider, shellInit); } @WMSingleton @Provides static HomeIntentProvider provideHomeIntentProvider(Context context) { return new HomeIntentProvider(context); } } libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +3 −28 Original line number Diff line number Diff line Loading @@ -85,6 +85,7 @@ import com.android.wm.shell.bubbles.BubbleController import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayLayout import com.android.wm.shell.common.ExternalInterfaceBinder import com.android.wm.shell.common.HomeIntentProvider import com.android.wm.shell.common.MultiInstanceHelper import com.android.wm.shell.common.MultiInstanceHelper.Companion.getComponent import com.android.wm.shell.common.RemoteCallable Loading Loading @@ -211,6 +212,7 @@ class DesktopTasksController( private val desktopModeCompatPolicy: DesktopModeCompatPolicy, private val dragToDisplayTransitionHandler: DragToDisplayTransitionHandler, private val moveToDisplayTransitionHandler: DesktopModeMoveToDisplayTransitionHandler, private val homeIntentProvider: HomeIntentProvider, ) : RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler, Loading Loading @@ -1718,34 +1720,7 @@ class DesktopTasksController( } private fun addLaunchHomePendingIntent(wct: WindowContainerTransaction, displayId: Int) { val userHandle = UserHandle.of(userId) val launchHomeIntent = Intent(Intent.ACTION_MAIN).apply { if (displayId != DEFAULT_DISPLAY) { addCategory(Intent.CATEGORY_SECONDARY_HOME) } else { addCategory(Intent.CATEGORY_HOME) } } val options = ActivityOptions.makeBasic().apply { launchWindowingMode = WINDOWING_MODE_FULLSCREEN pendingIntentBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS if (Flags.enablePerDisplayDesktopWallpaperActivity()) { launchDisplayId = displayId } } val pendingIntent = PendingIntent.getActivityAsUser( context, /* requestCode= */ 0, launchHomeIntent, PendingIntent.FLAG_IMMUTABLE, /* options= */ null, userHandle, ) wct.sendPendingIntent(pendingIntent, launchHomeIntent, options.toBundle()) homeIntentProvider.addLaunchHomePendingIntent(wct, displayId, userId) } private fun addWallpaperActivity(displayId: Int, wct: WindowContainerTransaction) { Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/common/HomeIntentProvider.kt 0 → 100644 +65 −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.wm.shell.common import android.app.ActivityManager import android.app.ActivityOptions import android.app.PendingIntent import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.content.Context import android.content.Intent import android.os.UserHandle import android.view.Display.DEFAULT_DISPLAY import android.window.WindowContainerTransaction import com.android.window.flags.Flags /** Creates home intent **/ class HomeIntentProvider( private val context: Context, ) { fun addLaunchHomePendingIntent( wct: WindowContainerTransaction, displayId: Int, userId: Int? = null ) { val userHandle = if (userId != null) UserHandle.of(userId) else UserHandle.of(ActivityManager.getCurrentUser()) val launchHomeIntent = Intent(Intent.ACTION_MAIN).apply { if (displayId != DEFAULT_DISPLAY) { addCategory(Intent.CATEGORY_SECONDARY_HOME) } else { addCategory(Intent.CATEGORY_HOME) } } val options = ActivityOptions.makeBasic().apply { launchWindowingMode = WINDOWING_MODE_FULLSCREEN pendingIntentBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS if (Flags.enablePerDisplayDesktopWallpaperActivity()) { launchDisplayId = displayId } } val pendingIntent = PendingIntent.getActivityAsUser( context, /* requestCode= */ 0, launchHomeIntent, PendingIntent.FLAG_IMMUTABLE, /* options= */ null, userHandle, ) wct.sendPendingIntent(pendingIntent, launchHomeIntent, options.toBundle()) } } No newline at end of file
libs/WindowManager/Shell/src/com/android/wm/shell/crashhandling/OWNERS 0 → 100644 +2 −0 Original line number Diff line number Diff line # WM shell sub-module crash handling owners uysalorhan@google.com No newline at end of file
libs/WindowManager/Shell/src/com/android/wm/shell/crashhandling/ShellCrashHandler.kt 0 → 100644 +75 −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.wm.shell.crashhandling import android.app.WindowConfiguration import android.content.Context import android.view.Display.DEFAULT_DISPLAY import android.window.DesktopExperienceFlags import android.window.WindowContainerTransaction import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.common.HomeIntentProvider import com.android.wm.shell.shared.desktopmode.DesktopModeStatus import com.android.wm.shell.sysui.ShellInit /** [ShellCrashHandler] for shell to use when it's being initialized. Currently it only restores * the home task to top. **/ class ShellCrashHandler( private val context: Context, private val shellTaskOrganizer: ShellTaskOrganizer, private val homeIntentProvider: HomeIntentProvider, shellInit: ShellInit, ) { init { shellInit.addInitCallback(::onInit, this) } private fun onInit() { handleCrashIfNeeded() } private fun handleCrashIfNeeded() { // For now only handle crashes when desktop mode is enabled on the device. if (DesktopModeStatus.canEnterDesktopMode(context) && !DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { var freeformTaskExists = false // If there are running tasks at init, WMShell has crashed but WMCore is still alive. for (task in shellTaskOrganizer.getRunningTasks()) { if (task.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM) { freeformTaskExists = true } if (freeformTaskExists) { shellTaskOrganizer.applyTransaction( addLaunchHomePendingIntent(WindowContainerTransaction(), DEFAULT_DISPLAY) ) break } } } } private fun addLaunchHomePendingIntent( wct: WindowContainerTransaction, displayId: Int ): WindowContainerTransaction { // TODO: b/400462917 - Check that crashes are also handled correctly on HSUM devices. We // might need to pass the [userId] here to launch the correct home. homeIntentProvider.addLaunchHomePendingIntent(wct, displayId) return wct } } No newline at end of file
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +24 −3 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.FloatingContentCoordinator; import com.android.wm.shell.common.HomeIntentProvider; import com.android.wm.shell.common.LaunchAdjacentController; import com.android.wm.shell.common.MultiDisplayDragMoveIndicatorController; import com.android.wm.shell.common.MultiDisplayDragMoveIndicatorSurface; Loading @@ -80,6 +81,7 @@ import com.android.wm.shell.common.UserProfileContexts; import com.android.wm.shell.common.split.SplitState; import com.android.wm.shell.compatui.letterbox.LetterboxCommandHandler; import com.android.wm.shell.compatui.letterbox.LetterboxTransitionObserver; import com.android.wm.shell.crashhandling.ShellCrashHandler; import com.android.wm.shell.dagger.back.ShellBackAnimationModule; import com.android.wm.shell.dagger.pip.PipModule; import com.android.wm.shell.desktopmode.CloseDesktopTaskTransitionHandler; Loading Loading @@ -779,7 +781,8 @@ public abstract class WMShellModule { UserProfileContexts userProfileContexts, DesktopModeCompatPolicy desktopModeCompatPolicy, DragToDisplayTransitionHandler dragToDisplayTransitionHandler, DesktopModeMoveToDisplayTransitionHandler moveToDisplayTransitionHandler) { DesktopModeMoveToDisplayTransitionHandler moveToDisplayTransitionHandler, HomeIntentProvider homeIntentProvider) { return new DesktopTasksController( context, shellInit, Loading Loading @@ -820,7 +823,8 @@ public abstract class WMShellModule { userProfileContexts, desktopModeCompatPolicy, dragToDisplayTransitionHandler, moveToDisplayTransitionHandler); moveToDisplayTransitionHandler, homeIntentProvider); } @WMSingleton Loading Loading @@ -1544,7 +1548,8 @@ public abstract class WMShellModule { Optional<DesktopTasksTransitionObserver> desktopTasksTransitionObserverOptional, Optional<DesktopDisplayEventHandler> desktopDisplayEventHandler, Optional<DesktopModeKeyGestureHandler> desktopModeKeyGestureHandler, Optional<SystemModalsTransitionHandler> systemModalsTransitionHandler) { Optional<SystemModalsTransitionHandler> systemModalsTransitionHandler, ShellCrashHandler shellCrashHandler) { return new Object(); } Loading @@ -1564,4 +1569,20 @@ public abstract class WMShellModule { return new UserProfileContexts(context, shellController, shellInit); } @WMSingleton @Provides static ShellCrashHandler provideShellCrashHandler( Context context, ShellTaskOrganizer shellTaskOrganizer, HomeIntentProvider homeIntentProvider, ShellInit shellInit) { return new ShellCrashHandler(context, shellTaskOrganizer, homeIntentProvider, shellInit); } @WMSingleton @Provides static HomeIntentProvider provideHomeIntentProvider(Context context) { return new HomeIntentProvider(context); } }
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +3 −28 Original line number Diff line number Diff line Loading @@ -85,6 +85,7 @@ import com.android.wm.shell.bubbles.BubbleController import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayLayout import com.android.wm.shell.common.ExternalInterfaceBinder import com.android.wm.shell.common.HomeIntentProvider import com.android.wm.shell.common.MultiInstanceHelper import com.android.wm.shell.common.MultiInstanceHelper.Companion.getComponent import com.android.wm.shell.common.RemoteCallable Loading Loading @@ -211,6 +212,7 @@ class DesktopTasksController( private val desktopModeCompatPolicy: DesktopModeCompatPolicy, private val dragToDisplayTransitionHandler: DragToDisplayTransitionHandler, private val moveToDisplayTransitionHandler: DesktopModeMoveToDisplayTransitionHandler, private val homeIntentProvider: HomeIntentProvider, ) : RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler, Loading Loading @@ -1718,34 +1720,7 @@ class DesktopTasksController( } private fun addLaunchHomePendingIntent(wct: WindowContainerTransaction, displayId: Int) { val userHandle = UserHandle.of(userId) val launchHomeIntent = Intent(Intent.ACTION_MAIN).apply { if (displayId != DEFAULT_DISPLAY) { addCategory(Intent.CATEGORY_SECONDARY_HOME) } else { addCategory(Intent.CATEGORY_HOME) } } val options = ActivityOptions.makeBasic().apply { launchWindowingMode = WINDOWING_MODE_FULLSCREEN pendingIntentBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS if (Flags.enablePerDisplayDesktopWallpaperActivity()) { launchDisplayId = displayId } } val pendingIntent = PendingIntent.getActivityAsUser( context, /* requestCode= */ 0, launchHomeIntent, PendingIntent.FLAG_IMMUTABLE, /* options= */ null, userHandle, ) wct.sendPendingIntent(pendingIntent, launchHomeIntent, options.toBundle()) homeIntentProvider.addLaunchHomePendingIntent(wct, displayId, userId) } private fun addWallpaperActivity(displayId: Int, wct: WindowContainerTransaction) { Loading