Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/WindowDecorCaptionRepository.kt +10 −6 Original line number Diff line number Diff line Loading @@ -22,22 +22,26 @@ import com.android.wm.shell.desktopmode.CaptionState.AppHandle import com.android.wm.shell.desktopmode.CaptionState.AppHeader import com.android.wm.shell.desktopmode.CaptionState.NoCaption import com.android.wm.shell.windowdecor.viewholder.AppHandleIdentifier import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow /** Repository to observe caption state. */ class WindowDecorCaptionRepository { private val _captionStateFlow = MutableStateFlow<CaptionState>(NoCaption()) /** Observer for app handle state changes. */ val captionStateFlow: StateFlow<CaptionState> = _captionStateFlow private val _captionStateFlow = MutableSharedFlow<CaptionState>( replay = 2, extraBufferCapacity = 5, onBufferOverflow = BufferOverflow.DROP_OLDEST, ) /** Observer for caption state changes. */ val captionStateFlow = _captionStateFlow private val _appToWebUsageFlow = MutableSharedFlow<Unit>() /** Observer for App-to-Web usage. */ val appToWebUsageFlow = _appToWebUsageFlow /** Notifies [captionStateFlow] if there is a change to caption state. */ fun notifyCaptionChanged(captionState: CaptionState) { _captionStateFlow.value = captionState _captionStateFlow.tryEmit(captionState) } /** Notifies [appToWebUsageFlow] if App-to-Web feature is used. */ Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/caption/AppHandleController.kt +28 −9 Original line number Diff line number Diff line Loading @@ -202,12 +202,12 @@ class AppHandleController( private fun notifyNoCaption() { if (!desktopState.canEnterDesktopMode || !isEducationOrHandleReportingEnabled) return windowDecorHandleRepository.notifyCaptionChanged(CaptionState.NoCaption()) windowDecorHandleRepository.notifyCaptionChanged(CaptionState.NoCaption(taskInfo.taskId)) } private fun notifyCaptionStateChanged(captionLayoutResult: CaptionRelayoutResult) { if (!desktopState.canEnterDesktopMode || !isEducationOrHandleReportingEnabled) return if (!isCaptionVisible || !hasGlobalFocus) { if (!isCaptionVisible) { notifyNoCaption() return } Loading Loading @@ -248,14 +248,33 @@ class AppHandleController( } /** Returns the current bounds relative to the parent task. */ private fun getCurrentAppHandleBounds(captionLayoutResult: CaptionRelayoutResult): Rect = private fun getCurrentAppHandleBounds(captionLayoutResult: CaptionRelayoutResult): Rect { val bounds = Rect( captionLayoutResult.captionX, captionLayoutResult.captionY, captionLayoutResult.captionX + captionLayoutResult.captionWidth, captionLayoutResult.captionHeight, captionLayoutResult.captionY + captionLayoutResult.captionHeight, ) if ( splitScreenController.getSplitPosition(taskInfo.taskId) == SPLIT_POSITION_BOTTOM_OR_RIGHT ) { if (splitScreenController.isLeftRightSplit) { // If this is the right split task, add left stage's width. val rightStageBounds = Rect().also { splitScreenController.getStageBounds(Rect(), it) } bounds.offset(rightStageBounds.left, /* dy= */ 0) } else { val bottomStageBounds = Rect().also { splitScreenController.getRefStageBounds(Rect(), it) } bounds.offset(/* dx= */ 0, bottomStageBounds.top) } } return bounds } /** * Dispose of the view used to forward inputs in status bar region. Intended to be used any time * handle is no longer visible. Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/caption/AppHeaderController.kt +10 −8 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.view.SurfaceControl import android.view.View import android.view.View.OnLongClickListener import android.view.WindowInsets import android.window.DesktopExperienceFlags import android.window.DesktopModeFlags import android.window.TaskSnapshot import android.window.WindowContainerTransaction Loading Loading @@ -180,9 +181,10 @@ class AppHeaderController( get() = displayController.getDisplay(taskInfo.displayId) private val closeMaximizeWindowRunnable = Runnable { closeMaximizeMenu() } private val isEducationEnabled = private val isEducationOrHandleReportingEnabled = Flags.enableDesktopWindowingAppHandleEducation() || Flags.enableDesktopWindowingAppToWebEducationIntegration() Flags.enableDesktopWindowingAppToWebEducationIntegration() || DesktopExperienceFlags.ENABLE_APP_HANDLE_POSITION_REPORTING.isTrue private var isMaximizeMenuHovered = false private var isAppHeaderMaximizeButtonHovered = false Loading Loading @@ -260,7 +262,7 @@ class AppHeaderController( } private fun notifyCaptionStateChanged() { if (!desktopState.canEnterDesktopMode || !isEducationEnabled) { if (!desktopState.canEnterDesktopMode || !isEducationOrHandleReportingEnabled) { return } if (!isCaptionVisible || !hasGlobalFocus) { Loading @@ -271,8 +273,8 @@ class AppHeaderController( } private fun notifyNoCaption() { if (!desktopState.canEnterDesktopMode || !isEducationEnabled) return windowDecorCaptionRepository.notifyCaptionChanged(CaptionState.NoCaption()) if (!desktopState.canEnterDesktopMode || !isEducationOrHandleReportingEnabled) return windowDecorCaptionRepository.notifyCaptionChanged(CaptionState.NoCaption(taskInfo.taskId)) } private fun notifyAppHeaderStateChanged() { Loading Loading @@ -553,7 +555,7 @@ class AppHeaderController( viewHolder.onHandleMenuClosed() handleMenu?.close() handleMenu = null if (desktopState.canEnterDesktopMode && isEducationEnabled) { if (desktopState.canEnterDesktopMode && isEducationOrHandleReportingEnabled) { notifyCaptionStateChanged() } } Loading Loading @@ -637,7 +639,7 @@ class AppHeaderController( val (name, icon) = taskResourceLoader.getNameAndHeaderIcon(taskInfo) viewHolder.setAppName(name) viewHolder.setAppIcon(icon) if (desktopState.canEnterDesktopMode && isEducationEnabled) { if (desktopState.canEnterDesktopMode && isEducationOrHandleReportingEnabled) { notifyCaptionStateChanged() } } Loading Loading @@ -731,7 +733,7 @@ class AppHeaderController( closeManageWindowsMenu() closeMaximizeMenu() viewHolder.close() if (desktopState.canEnterDesktopMode && isEducationEnabled) { if (desktopState.canEnterDesktopMode && isEducationOrHandleReportingEnabled) { notifyNoCaption() } return super.close(wct, t) Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/caption/CaptionController.kt +2 −0 Original line number Diff line number Diff line Loading @@ -550,7 +550,9 @@ abstract class CaptionController<T>( // The caption height with caption padding included val captionHeight: Int, val captionWidth: Int, // The caption x position relative to its parent task val captionX: Int, // The caption y position relative to its parent task val captionY: Int, val captionTopPadding: Int, val customizableCaptionRegion: Region, Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt +1 −9 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.View.OnLongClickListener import android.view.ViewTreeObserver.OnGlobalLayoutListener import android.view.accessibility.AccessibilityEvent import android.view.accessibility.AccessibilityNodeInfo import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction Loading Loading @@ -720,14 +719,7 @@ class AppHeaderViewHolder( fun runOnAppChipGlobalLayout(runnable: () -> Unit) { // Wait for app chip to be inflated before notifying repository. openMenuButton.viewTreeObserver.addOnGlobalLayoutListener( object : OnGlobalLayoutListener { override fun onGlobalLayout() { runnable() openMenuButton.viewTreeObserver.removeOnGlobalLayoutListener(this) } } ) openMenuButton.post { runnable() } } fun getAppChipLocationInWindow(): Rect { Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/WindowDecorCaptionRepository.kt +10 −6 Original line number Diff line number Diff line Loading @@ -22,22 +22,26 @@ import com.android.wm.shell.desktopmode.CaptionState.AppHandle import com.android.wm.shell.desktopmode.CaptionState.AppHeader import com.android.wm.shell.desktopmode.CaptionState.NoCaption import com.android.wm.shell.windowdecor.viewholder.AppHandleIdentifier import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow /** Repository to observe caption state. */ class WindowDecorCaptionRepository { private val _captionStateFlow = MutableStateFlow<CaptionState>(NoCaption()) /** Observer for app handle state changes. */ val captionStateFlow: StateFlow<CaptionState> = _captionStateFlow private val _captionStateFlow = MutableSharedFlow<CaptionState>( replay = 2, extraBufferCapacity = 5, onBufferOverflow = BufferOverflow.DROP_OLDEST, ) /** Observer for caption state changes. */ val captionStateFlow = _captionStateFlow private val _appToWebUsageFlow = MutableSharedFlow<Unit>() /** Observer for App-to-Web usage. */ val appToWebUsageFlow = _appToWebUsageFlow /** Notifies [captionStateFlow] if there is a change to caption state. */ fun notifyCaptionChanged(captionState: CaptionState) { _captionStateFlow.value = captionState _captionStateFlow.tryEmit(captionState) } /** Notifies [appToWebUsageFlow] if App-to-Web feature is used. */ Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/caption/AppHandleController.kt +28 −9 Original line number Diff line number Diff line Loading @@ -202,12 +202,12 @@ class AppHandleController( private fun notifyNoCaption() { if (!desktopState.canEnterDesktopMode || !isEducationOrHandleReportingEnabled) return windowDecorHandleRepository.notifyCaptionChanged(CaptionState.NoCaption()) windowDecorHandleRepository.notifyCaptionChanged(CaptionState.NoCaption(taskInfo.taskId)) } private fun notifyCaptionStateChanged(captionLayoutResult: CaptionRelayoutResult) { if (!desktopState.canEnterDesktopMode || !isEducationOrHandleReportingEnabled) return if (!isCaptionVisible || !hasGlobalFocus) { if (!isCaptionVisible) { notifyNoCaption() return } Loading Loading @@ -248,14 +248,33 @@ class AppHandleController( } /** Returns the current bounds relative to the parent task. */ private fun getCurrentAppHandleBounds(captionLayoutResult: CaptionRelayoutResult): Rect = private fun getCurrentAppHandleBounds(captionLayoutResult: CaptionRelayoutResult): Rect { val bounds = Rect( captionLayoutResult.captionX, captionLayoutResult.captionY, captionLayoutResult.captionX + captionLayoutResult.captionWidth, captionLayoutResult.captionHeight, captionLayoutResult.captionY + captionLayoutResult.captionHeight, ) if ( splitScreenController.getSplitPosition(taskInfo.taskId) == SPLIT_POSITION_BOTTOM_OR_RIGHT ) { if (splitScreenController.isLeftRightSplit) { // If this is the right split task, add left stage's width. val rightStageBounds = Rect().also { splitScreenController.getStageBounds(Rect(), it) } bounds.offset(rightStageBounds.left, /* dy= */ 0) } else { val bottomStageBounds = Rect().also { splitScreenController.getRefStageBounds(Rect(), it) } bounds.offset(/* dx= */ 0, bottomStageBounds.top) } } return bounds } /** * Dispose of the view used to forward inputs in status bar region. Intended to be used any time * handle is no longer visible. Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/caption/AppHeaderController.kt +10 −8 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.view.SurfaceControl import android.view.View import android.view.View.OnLongClickListener import android.view.WindowInsets import android.window.DesktopExperienceFlags import android.window.DesktopModeFlags import android.window.TaskSnapshot import android.window.WindowContainerTransaction Loading Loading @@ -180,9 +181,10 @@ class AppHeaderController( get() = displayController.getDisplay(taskInfo.displayId) private val closeMaximizeWindowRunnable = Runnable { closeMaximizeMenu() } private val isEducationEnabled = private val isEducationOrHandleReportingEnabled = Flags.enableDesktopWindowingAppHandleEducation() || Flags.enableDesktopWindowingAppToWebEducationIntegration() Flags.enableDesktopWindowingAppToWebEducationIntegration() || DesktopExperienceFlags.ENABLE_APP_HANDLE_POSITION_REPORTING.isTrue private var isMaximizeMenuHovered = false private var isAppHeaderMaximizeButtonHovered = false Loading Loading @@ -260,7 +262,7 @@ class AppHeaderController( } private fun notifyCaptionStateChanged() { if (!desktopState.canEnterDesktopMode || !isEducationEnabled) { if (!desktopState.canEnterDesktopMode || !isEducationOrHandleReportingEnabled) { return } if (!isCaptionVisible || !hasGlobalFocus) { Loading @@ -271,8 +273,8 @@ class AppHeaderController( } private fun notifyNoCaption() { if (!desktopState.canEnterDesktopMode || !isEducationEnabled) return windowDecorCaptionRepository.notifyCaptionChanged(CaptionState.NoCaption()) if (!desktopState.canEnterDesktopMode || !isEducationOrHandleReportingEnabled) return windowDecorCaptionRepository.notifyCaptionChanged(CaptionState.NoCaption(taskInfo.taskId)) } private fun notifyAppHeaderStateChanged() { Loading Loading @@ -553,7 +555,7 @@ class AppHeaderController( viewHolder.onHandleMenuClosed() handleMenu?.close() handleMenu = null if (desktopState.canEnterDesktopMode && isEducationEnabled) { if (desktopState.canEnterDesktopMode && isEducationOrHandleReportingEnabled) { notifyCaptionStateChanged() } } Loading Loading @@ -637,7 +639,7 @@ class AppHeaderController( val (name, icon) = taskResourceLoader.getNameAndHeaderIcon(taskInfo) viewHolder.setAppName(name) viewHolder.setAppIcon(icon) if (desktopState.canEnterDesktopMode && isEducationEnabled) { if (desktopState.canEnterDesktopMode && isEducationOrHandleReportingEnabled) { notifyCaptionStateChanged() } } Loading Loading @@ -731,7 +733,7 @@ class AppHeaderController( closeManageWindowsMenu() closeMaximizeMenu() viewHolder.close() if (desktopState.canEnterDesktopMode && isEducationEnabled) { if (desktopState.canEnterDesktopMode && isEducationOrHandleReportingEnabled) { notifyNoCaption() } return super.close(wct, t) Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/caption/CaptionController.kt +2 −0 Original line number Diff line number Diff line Loading @@ -550,7 +550,9 @@ abstract class CaptionController<T>( // The caption height with caption padding included val captionHeight: Int, val captionWidth: Int, // The caption x position relative to its parent task val captionX: Int, // The caption y position relative to its parent task val captionY: Int, val captionTopPadding: Int, val customizableCaptionRegion: Region, Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt +1 −9 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.View.OnLongClickListener import android.view.ViewTreeObserver.OnGlobalLayoutListener import android.view.accessibility.AccessibilityEvent import android.view.accessibility.AccessibilityNodeInfo import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction Loading Loading @@ -720,14 +719,7 @@ class AppHeaderViewHolder( fun runOnAppChipGlobalLayout(runnable: () -> Unit) { // Wait for app chip to be inflated before notifying repository. openMenuButton.viewTreeObserver.addOnGlobalLayoutListener( object : OnGlobalLayoutListener { override fun onGlobalLayout() { runnable() openMenuButton.viewTreeObserver.removeOnGlobalLayoutListener(this) } } ) openMenuButton.post { runnable() } } fun getAppChipLocationInWindow(): Rect { Loading