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