diff options
7 files changed, 54 insertions, 118 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java index 2d7fec3a5302..5e8c1fe2aa8d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java @@ -445,4 +445,9 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL private static int getCaptionHeightIdStatic(@WindowingMode int windowingMode) { return R.dimen.freeform_decor_caption_height; } + + @Override + int getCaptionViewId() { + return R.id.caption; + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecoration.java index 88f64bca280d..3182745d813e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecoration.java @@ -108,6 +108,11 @@ public class CarWindowDecoration extends WindowDecoration<WindowDecorLinearLayou return new Rect(); } + @Override + int getCaptionViewId() { + return R.id.caption; + } + private void updateRelayoutParams( RelayoutParams relayoutParams, ActivityManager.RunningTaskInfo taskInfo, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index 813d0c6fcb6c..2a5315739396 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -1769,6 +1769,11 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin return loadDimensionPixelSize(mContext.getResources(), getCaptionHeightId(windowingMode)); } + @Override + int getCaptionViewId() { + return R.id.desktop_mode_caption; + } + void setAnimatingTaskResizeOrReposition(boolean animatingTaskResizeOrReposition) { if (mRelayoutParams.mLayoutResId == R.layout.desktop_mode_app_handle) return; final boolean inFullImmersive = diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java index dc4a19e54df4..7baef2b2dc97 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java @@ -625,16 +625,32 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> */ private void updateCaptionVisibility(View rootView, @NonNull RelayoutParams params) { mIsCaptionVisible = params.mIsCaptionVisible; + setCaptionVisibility(rootView, mIsCaptionVisible); } void setTaskDragResizer(TaskDragResizer taskDragResizer) { mTaskDragResizer = taskDragResizer; } + // TODO(b/346441962): Move these three methods closer to implementing or View-level classes to + // keep implementation details more encapsulated. + private void setCaptionVisibility(View rootView, boolean visible) { + if (rootView == null) { + return; + } + final int v = visible ? View.VISIBLE : View.GONE; + final View captionView = rootView.findViewById(getCaptionViewId()); + captionView.setVisibility(v); + } + int getCaptionHeightId(@WindowingMode int windowingMode) { return Resources.ID_NULL; } + int getCaptionViewId() { + return Resources.ID_NULL; + } + /** * Obtains the {@link Display} instance for the display ID in {@link #mTaskInfo} if it exists or * registers {@link #mOnDisplaysChangedListener} if it doesn't. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleAnimator.kt deleted file mode 100644 index f0a85306d177..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleAnimator.kt +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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.windowdecor - -import android.animation.ObjectAnimator -import android.view.View -import android.view.View.Visibility -import android.view.animation.PathInterpolator -import android.widget.ImageButton -import androidx.core.animation.doOnEnd -import com.android.wm.shell.shared.animation.Interpolators - -/** - * Animates the Desktop View's app handle. - */ -class AppHandleAnimator( - private val appHandleView: View, - private val captionHandle: ImageButton, -) { - companion object { - // Constants for animating the whole caption - private const val APP_HANDLE_ALPHA_FADE_IN_ANIMATION_DURATION_MS: Long = 275L - private const val APP_HANDLE_ALPHA_FADE_OUT_ANIMATION_DURATION_MS: Long = 340 - private val APP_HANDLE_ANIMATION_INTERPOLATOR = PathInterpolator( - 0.4f, - 0f, - 0.2f, - 1f - ) - - // Constants for animating the caption's handle - private const val HANDLE_ANIMATION_DURATION: Long = 100 - private val HANDLE_ANIMATION_INTERPOLATOR = Interpolators.FAST_OUT_SLOW_IN - } - - private var animator: ObjectAnimator? = null - - /** Animates the given caption view to the given visibility after a visibility change. */ - fun animateVisibilityChange(@Visibility visible: Int) { - when (visible) { - View.VISIBLE -> animateShowAppHandle() - else -> animateHideAppHandle() - } - } - - /** Animate appearance/disappearance of caption's handle. */ - fun animateCaptionHandleAlpha(startValue: Float, endValue: Float) { - cancel() - animator = ObjectAnimator.ofFloat(captionHandle, View.ALPHA, startValue, endValue).apply { - duration = HANDLE_ANIMATION_DURATION - interpolator = HANDLE_ANIMATION_INTERPOLATOR - start() - } - } - - private fun animateShowAppHandle() { - cancel() - appHandleView.alpha = 0f - appHandleView.visibility = View.VISIBLE - animator = ObjectAnimator.ofFloat(appHandleView, View.ALPHA, 1f).apply { - duration = APP_HANDLE_ALPHA_FADE_IN_ANIMATION_DURATION_MS - interpolator = APP_HANDLE_ANIMATION_INTERPOLATOR - start() - } - } - - private fun animateHideAppHandle() { - cancel() - animator = ObjectAnimator.ofFloat(appHandleView, View.ALPHA, 0f).apply { - duration = APP_HANDLE_ALPHA_FADE_OUT_ANIMATION_DURATION_MS - interpolator = APP_HANDLE_ANIMATION_INTERPOLATOR - doOnEnd { - appHandleView.visibility = View.GONE - } - start() - } - } - - /** - * Cancels any active animations. - */ - fun cancel() { - animator?.removeAllListeners() - animator?.cancel() - animator = null - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt index 7ab3303be618..d9df899f8b40 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt @@ -15,6 +15,7 @@ */ package com.android.wm.shell.windowdecor.viewholder +import android.animation.ObjectAnimator import android.app.ActivityManager.RunningTaskInfo import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.content.res.ColorStateList @@ -39,8 +40,8 @@ import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.Accessibilit import com.android.internal.policy.SystemBarUtils import com.android.window.flags.Flags import com.android.wm.shell.R +import com.android.wm.shell.shared.animation.Interpolators import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper -import com.android.wm.shell.windowdecor.AppHandleAnimator import com.android.wm.shell.windowdecor.WindowManagerWrapper import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer @@ -56,6 +57,10 @@ internal class AppHandleViewHolder( private val handler: Handler ) : WindowDecorationViewHolder<AppHandleViewHolder.HandleData>(rootView) { + companion object { + private const val CAPTION_HANDLE_ANIMATION_DURATION: Long = 100 + } + data class HandleData( val taskInfo: RunningTaskInfo, val position: Point, @@ -68,7 +73,6 @@ internal class AppHandleViewHolder( private val captionView: View = rootView.requireViewById(R.id.desktop_mode_caption) private val captionHandle: ImageButton = rootView.requireViewById(R.id.caption_handle) private val inputManager = context.getSystemService(InputManager::class.java) - private val animator: AppHandleAnimator = AppHandleAnimator(rootView, captionHandle) private var statusBarInputLayerExists = false // An invisible View that takes up the same coordinates as captionHandle but is layered @@ -107,7 +111,6 @@ internal class AppHandleViewHolder( height: Int, isCaptionVisible: Boolean ) { - setVisibility(isCaptionVisible) captionHandle.imageTintList = ColorStateList.valueOf(getCaptionHandleBarColor(taskInfo)) this.taskInfo = taskInfo // If handle is not in status bar region(i.e., bottom stage in vertical split), @@ -129,11 +132,11 @@ internal class AppHandleViewHolder( } override fun onHandleMenuOpened() { - animator.animateCaptionHandleAlpha(startValue = 1f, endValue = 0f) + animateCaptionHandleAlpha(startValue = 1f, endValue = 0f) } override fun onHandleMenuClosed() { - animator.animateCaptionHandleAlpha(startValue = 0f, endValue = 1f) + animateCaptionHandleAlpha(startValue = 0f, endValue = 1f) } private fun createStatusBarInputLayer(handlePosition: Point, @@ -237,16 +240,6 @@ internal class AppHandleViewHolder( } } - private fun setVisibility(visible: Boolean) { - val v = if (visible) View.VISIBLE else View.GONE - if (captionView.visibility == v) return - if (!DesktopModeFlags.ENABLE_DESKTOP_APP_HANDLE_ANIMATION.isTrue()) { - captionView.visibility = v - return - } - animator.animateVisibilityChange(v) - } - private fun getCaptionHandleBarColor(taskInfo: RunningTaskInfo): Int { return if (shouldUseLightCaptionColors(taskInfo)) { context.getColor(R.color.desktop_mode_caption_handle_bar_light) @@ -272,7 +265,15 @@ internal class AppHandleViewHolder( } ?: false } - override fun close() { - animator.cancel() + /** Animate appearance/disappearance of caption handle as the handle menu is animated. */ + private fun animateCaptionHandleAlpha(startValue: Float, endValue: Float) { + val animator = + ObjectAnimator.ofFloat(captionHandle, View.ALPHA, startValue, endValue).apply { + duration = CAPTION_HANDLE_ANIMATION_DURATION + interpolator = Interpolators.FAST_OUT_SLOW_IN + } + animator.start() } + + override fun close() {} } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java index d8d043eac1ee..a2927fa3527b 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java @@ -1186,6 +1186,11 @@ public class WindowDecorationTests extends ShellTestCase { } @Override + int getCaptionViewId() { + return R.id.caption; + } + + @Override TestView inflateLayout(Context context, int layoutResId) { if (layoutResId == R.layout.caption_layout) { return mMockView; |