diff options
| author | 2024-11-15 12:22:54 +0000 | |
|---|---|---|
| committer | 2024-11-15 12:22:54 +0000 | |
| commit | 0d0270676a0b91a844e04b9909cd67e50fc9b030 (patch) | |
| tree | 5469518466e10834bf1127b4a639f8306ca10ea2 | |
| parent | 08091da75cf3ad077dc1923cdf1da75f1f59f596 (diff) | |
| parent | aad007bac5cee46f5260ba5f218a3729643ea62f (diff) | |
Merge "[3/n] Implement Letterbox Surfaces lifecycle" into main
4 files changed, 299 insertions, 0 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxController.kt new file mode 100644 index 000000000000..406823de8269 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxController.kt @@ -0,0 +1,150 @@ +/* + * Copyright 2024 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.compatui.letterbox + +import android.graphics.Color +import android.graphics.Rect +import android.view.SurfaceControl +import com.android.internal.protolog.ProtoLog +import com.android.wm.shell.dagger.WMSingleton +import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT +import javax.inject.Inject + +/** + * Component responsible for handling the lifecycle of the letterbox surfaces. + */ +@WMSingleton +class LetterboxController @Inject constructor() { + + companion object { + /* + * Letterbox surfaces need to stay below the activity layer which is 0. + */ + // TODO(b/378673153): Consider adding this to [TaskConstants]. + @JvmStatic + private val TASK_CHILD_LAYER_LETTERBOX_BACKGROUND = -1000 + @JvmStatic + private val TAG = "LetterboxController" + } + + private val letterboxMap = mutableMapOf<LetterboxKey, LetterboxItem>() + + /** + * Creates a Letterbox Surface for a given displayId/taskId if it doesn't exist. + */ + fun createLetterboxSurface( + key: LetterboxKey, + startTransaction: SurfaceControl.Transaction, + parentLeash: SurfaceControl + ) { + letterboxMap.runOnItem(key, onMissed = { k, m -> + m[k] = LetterboxItem( + SurfaceControl.Builder() + .setName("ShellLetterboxSurface-$key") + .setHidden(true) + .setColorLayer() + .setParent(parentLeash) + .setCallsite("LetterboxController-createLetterboxSurface") + .build().apply { + startTransaction.setLayer( + this, + TASK_CHILD_LAYER_LETTERBOX_BACKGROUND + ).setColorSpaceAgnostic(this, true) + // TODO(b/370940063): Implement LetterboxConfiguration + .setColor(this, Color.valueOf(Color.YELLOW).components) + } + ) + }) + } + + /** + * Invoked to destroy the surfaces for a letterbox session for given displayId/taskId. + */ + fun destroyLetterboxSurface( + key: LetterboxKey, + startTransaction: SurfaceControl.Transaction + ) { + letterboxMap.runOnItem(key, onFound = { item -> + item.fullWindowSurface?.run { + startTransaction.remove(this) + } + }) + letterboxMap.remove(key) + } + + /** + * Invoked to show/hide the letterbox surfaces for given displayId/taskId. + */ + fun updateLetterboxSurfaceVisibility( + key: LetterboxKey, + startTransaction: SurfaceControl.Transaction, + visible: Boolean = true + ) { + letterboxMap.runOnItem(key, onFound = { item -> + item.fullWindowSurface?.run { + startTransaction.setVisibility(this, visible) + } + }) + } + + /** + * Updates the bounds for the letterbox surfaces for given displayId/taskId. + */ + fun updateLetterboxSurfaceBounds( + key: LetterboxKey, + startTransaction: SurfaceControl.Transaction, + bounds: Rect + ) { + letterboxMap.runOnItem(key, onFound = { item -> + item.fullWindowSurface?.run { + startTransaction.moveAndCrop(this, bounds) + } + }) + } + + /* + * Executes [onFound] on the [LetterboxItem] if present or [onMissed] if not present. + */ + private fun MutableMap<LetterboxKey, LetterboxItem>.runOnItem( + key: LetterboxKey, + onFound: (LetterboxItem) -> Unit = { _ -> }, + onMissed: ( + LetterboxKey, + MutableMap<LetterboxKey, LetterboxItem> + ) -> Unit = { _, _ -> } + ) { + this[key]?.let { + return onFound(it) + } + return onMissed(key, this) + } + + fun dump() { + ProtoLog.v(WM_SHELL_APP_COMPAT, "%s: %s", TAG, "${letterboxMap.keys}") + } + + private fun SurfaceControl.Transaction.moveAndCrop( + surface: SurfaceControl, + rect: Rect + ): SurfaceControl.Transaction = + setPosition(surface, rect.left.toFloat(), rect.top.toFloat()) + .setWindowCrop( + surface, + rect.width(), + rect.height() + ) +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxData.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxData.kt new file mode 100644 index 000000000000..98fd2472f1e4 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxData.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2024 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.compatui.letterbox + +import android.view.SurfaceControl + +// The key to use for identify the letterbox sessions. +data class LetterboxKey(val displayId: Int, val taskId: Int) + +// Encapsulate the objects for the specific letterbox session. +data class LetterboxItem(val fullWindowSurface: SurfaceControl?)
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserver.kt new file mode 100644 index 000000000000..67429bdd112b --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserver.kt @@ -0,0 +1,106 @@ +/* + * Copyright 2024 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.compatui.letterbox + +import android.graphics.Rect +import android.os.IBinder +import android.view.SurfaceControl +import android.window.TransitionInfo +import com.android.internal.protolog.ProtoLog +import com.android.window.flags.Flags.appCompatRefactoring +import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT +import com.android.wm.shell.shared.TransitionUtil.isClosingType +import com.android.wm.shell.sysui.ShellInit +import com.android.wm.shell.transition.Transitions + +/** + * The [TransitionObserver] to handle Letterboxing events in Shell. + */ +class LetterboxTransitionObserver( + shellInit: ShellInit, + private val transitions: Transitions, + private val letterboxController: LetterboxController +) : Transitions.TransitionObserver { + + companion object { + @JvmStatic + private val TAG = "LetterboxTransitionObserver" + } + + init { + if (appCompatRefactoring()) { + ProtoLog.v( + WM_SHELL_APP_COMPAT, + "%s: %s", + TAG, + "Initializing LetterboxTransitionObserver" + ) + shellInit.addInitCallback({ + transitions.registerObserver(this) + }, this) + } + } + + override fun onTransitionReady( + transition: IBinder, + info: TransitionInfo, + startTransaction: SurfaceControl.Transaction, + finishTransaction: SurfaceControl.Transaction + ) { + // We recognise the operation to execute and delegate to the LetterboxController + // the related operation. + // TODO(b/377875151): Identify Desktop Windowing Transactions. + // TODO(b/377857898): Handling multiple surfaces + // TODO(b/371500295): Handle input events detection. + for (change in info.changes) { + change.taskInfo?.let { ti -> + val key = LetterboxKey(ti.displayId, ti.taskId) + if (isClosingType(change.mode)) { + letterboxController.destroyLetterboxSurface( + key, + startTransaction + ) + } else { + val isTopActivityLetterboxed = ti.appCompatTaskInfo.isTopActivityLetterboxed + if (isTopActivityLetterboxed) { + letterboxController.createLetterboxSurface( + key, + startTransaction, + change.leash + ) + letterboxController.updateLetterboxSurfaceBounds( + key, + startTransaction, + Rect( + change.endRelOffset.x, + change.endRelOffset.y, + change.endAbsBounds.width(), + change.endAbsBounds.height() + ) + ) + } + letterboxController.updateLetterboxSurfaceVisibility( + key, + startTransaction, + isTopActivityLetterboxed + ) + } + letterboxController.dump() + } + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index 601cf70b93ed..307e12ea7555 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -20,6 +20,7 @@ import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_ENTER_TRA import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT; import static android.window.DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.KeyguardManager; import android.content.Context; @@ -62,6 +63,8 @@ import com.android.wm.shell.common.MultiInstanceHelper; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.TaskStackListenerImpl; +import com.android.wm.shell.compatui.letterbox.LetterboxController; +import com.android.wm.shell.compatui.letterbox.LetterboxTransitionObserver; import com.android.wm.shell.dagger.back.ShellBackAnimationModule; import com.android.wm.shell.dagger.pip.PipModule; import com.android.wm.shell.desktopmode.CloseDesktopTaskTransitionHandler; @@ -1229,8 +1232,23 @@ public abstract class WMShellModule { @Provides static Object provideIndependentShellComponentsToCreate( DragAndDropController dragAndDropController, + @NonNull LetterboxTransitionObserver letterboxTransitionObserver, Optional<DesktopTasksTransitionObserver> desktopTasksTransitionObserverOptional, Optional<DesktopDisplayEventHandler> desktopDisplayEventHandler) { return new Object(); } + + // + // App Compat + // + + @WMSingleton + @Provides + static LetterboxTransitionObserver provideLetterboxTransitionObserver( + @NonNull ShellInit shellInit, + @NonNull Transitions transitions, + @NonNull LetterboxController letterboxController + ) { + return new LetterboxTransitionObserver(shellInit, transitions, letterboxController); + } } |