Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 555a6200 authored by Jorge Gil's avatar Jorge Gil Committed by Automerger Merge Worker
Browse files

Merge "Add double-tap to quick resize desktop tasks" into udc-qpr-dev am: 6b8fc869

parents be0d1562 6b8fc869
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler;
import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler;
import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformComponents;
import com.android.wm.shell.freeform.FreeformTaskListener;
@@ -690,6 +691,7 @@ public abstract class WMShellModule {
            Transitions transitions,
            EnterDesktopTaskTransitionHandler enterDesktopTransitionHandler,
            ExitDesktopTaskTransitionHandler exitDesktopTransitionHandler,
            ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler,
            @DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository,
            LaunchAdjacentController launchAdjacentController,
            @ShellMainThread ShellExecutor mainExecutor
@@ -697,7 +699,8 @@ public abstract class WMShellModule {
        return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController,
                displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer,
                transitions, enterDesktopTransitionHandler, exitDesktopTransitionHandler,
                desktopModeTaskRepository, launchAdjacentController, mainExecutor);
                toggleResizeDesktopTaskTransitionHandler, desktopModeTaskRepository,
                launchAdjacentController, mainExecutor);
    }

    @WMSingleton
@@ -707,6 +710,13 @@ public abstract class WMShellModule {
        return new EnterDesktopTaskTransitionHandler(transitions);
    }

    @WMSingleton
    @Provides
    static ToggleResizeDesktopTaskTransitionHandler provideToggleResizeDesktopTaskTransitionHandler(
            Transitions transitions) {
        return new ToggleResizeDesktopTaskTransitionHandler(transitions);
    }

    @WMSingleton
    @Provides
    static ExitDesktopTaskTransitionHandler provideExitDesktopTaskTransitionHandler(
+54 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.graphics.Rect
import android.graphics.Region
import android.os.IBinder
import android.os.SystemProperties
import android.util.DisplayMetrics.DENSITY_DEFAULT
import android.view.SurfaceControl
import android.view.WindowManager.TRANSIT_CHANGE
import android.view.WindowManager.TRANSIT_NONE
@@ -78,6 +79,8 @@ class DesktopTasksController(
        private val transitions: Transitions,
        private val enterDesktopTaskTransitionHandler: EnterDesktopTaskTransitionHandler,
        private val exitDesktopTaskTransitionHandler: ExitDesktopTaskTransitionHandler,
        private val toggleResizeDesktopTaskTransitionHandler:
        ToggleResizeDesktopTaskTransitionHandler,
        private val desktopModeTaskRepository: DesktopModeTaskRepository,
        private val launchAdjacentController: LaunchAdjacentController,
        @ShellMainThread private val mainExecutor: ShellExecutor
@@ -382,6 +385,49 @@ class DesktopTasksController(
        }
    }

    /** Quick-resizes a desktop task, toggling between the stable bounds and the default bounds. */
    fun toggleDesktopTaskSize(taskInfo: RunningTaskInfo, windowDecor: DesktopModeWindowDecoration) {
        val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return

        val stableBounds = Rect()
        displayLayout.getStableBounds(stableBounds)
        val destinationBounds = Rect()
        if (taskInfo.configuration.windowConfiguration.bounds == stableBounds) {
            // The desktop task is currently occupying the whole stable bounds, toggle to the
            // default bounds.
            getDefaultDesktopTaskBounds(
                density = taskInfo.configuration.densityDpi.toFloat() / DENSITY_DEFAULT,
                stableBounds = stableBounds,
                outBounds = destinationBounds
            )
        } else {
            // Toggle to the stable bounds.
            destinationBounds.set(stableBounds)
        }

        val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds)
        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
            toggleResizeDesktopTaskTransitionHandler.startTransition(
                wct,
                taskInfo.taskId,
                windowDecor
            )
        } else {
            shellTaskOrganizer.applyTransaction(wct)
        }
    }

    private fun getDefaultDesktopTaskBounds(density: Float, stableBounds: Rect, outBounds: Rect) {
        val width = (DESKTOP_MODE_DEFAULT_WIDTH_DP * density + 0.5f).toInt()
        val height = (DESKTOP_MODE_DEFAULT_HEIGHT_DP * density + 0.5f).toInt()
        outBounds.set(0, 0, width, height)
        // Center the task in stable bounds
        outBounds.offset(
            stableBounds.centerX() - outBounds.centerX(),
            stableBounds.centerY() - outBounds.centerY()
        )
    }

    /**
     * Get windowing move for a given `taskId`
     *
@@ -883,6 +929,14 @@ class DesktopTasksController(
            SystemProperties.getInt("persist.wm.debug.desktop_mode_density", 0)
        private val DESKTOP_DENSITY_ALLOWED_RANGE = (100..1000)

        // Override default freeform task width when desktop mode is enabled. In dips.
        private val DESKTOP_MODE_DEFAULT_WIDTH_DP =
            SystemProperties.getInt("persist.wm.debug.desktop_mode.default_width", 840)

        // Override default freeform task height when desktop mode is enabled. In dips.
        private val DESKTOP_MODE_DEFAULT_HEIGHT_DP =
            SystemProperties.getInt("persist.wm.debug.desktop_mode.default_height", 630)

        /**
         * Check if desktop density override is enabled
         */
+154 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.desktopmode

import android.animation.Animator
import android.animation.RectEvaluator
import android.animation.ValueAnimator
import android.graphics.Rect
import android.os.IBinder
import android.util.SparseArray
import android.view.SurfaceControl
import android.view.WindowManager.TRANSIT_CHANGE
import android.window.TransitionInfo
import android.window.TransitionRequestInfo
import android.window.WindowContainerTransaction
import androidx.core.animation.addListener
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.transition.Transitions.TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE
import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration
import java.util.function.Supplier

/** Handles the animation of quick resizing of desktop tasks. */
class ToggleResizeDesktopTaskTransitionHandler(
    private val transitions: Transitions,
    private val transactionSupplier: Supplier<SurfaceControl.Transaction>
) : Transitions.TransitionHandler {

    private val rectEvaluator = RectEvaluator(Rect())
    private val taskToDecorationMap = SparseArray<DesktopModeWindowDecoration>()

    private var boundsAnimator: Animator? = null

    constructor(
        transitions: Transitions
    ) : this(transitions, Supplier { SurfaceControl.Transaction() })

    /** Starts a quick resize transition. */
    fun startTransition(
        wct: WindowContainerTransaction,
        taskId: Int,
        windowDecoration: DesktopModeWindowDecoration
    ) {
        // Pause relayout until the transition animation finishes.
        windowDecoration.incrementRelayoutBlock()
        transitions.startTransition(TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE, wct, this)
        taskToDecorationMap.put(taskId, windowDecoration)
    }

    override fun startAnimation(
        transition: IBinder,
        info: TransitionInfo,
        startTransaction: SurfaceControl.Transaction,
        finishTransaction: SurfaceControl.Transaction,
        finishCallback: Transitions.TransitionFinishCallback
    ): Boolean {
        val change = findRelevantChange(info)
        val leash = change.leash
        val taskId = change.taskInfo.taskId
        val startBounds = change.startAbsBounds
        val endBounds = change.endAbsBounds
        val windowDecor =
            taskToDecorationMap.removeReturnOld(taskId)
                ?: throw IllegalStateException("Window decoration not found for task $taskId")

        val tx = transactionSupplier.get()
        boundsAnimator?.cancel()
        boundsAnimator =
            ValueAnimator.ofObject(rectEvaluator, startBounds, endBounds)
                .setDuration(RESIZE_DURATION_MS)
                .apply {
                    addListener(
                        onStart = {
                            startTransaction
                                .setPosition(
                                    leash,
                                    startBounds.left.toFloat(),
                                    startBounds.top.toFloat()
                                )
                                .setWindowCrop(leash, startBounds.width(), startBounds.height())
                                .show(leash)
                            windowDecor.showResizeVeil(startTransaction, startBounds)
                        },
                        onEnd = {
                            finishTransaction
                                .setPosition(
                                    leash,
                                    endBounds.left.toFloat(),
                                    endBounds.top.toFloat()
                                )
                                .setWindowCrop(leash, endBounds.width(), endBounds.height())
                                .show(leash)
                            windowDecor.hideResizeVeil()
                            finishCallback.onTransitionFinished(null, null)
                            boundsAnimator = null
                        }
                    )
                    addUpdateListener { anim ->
                        val rect = anim.animatedValue as Rect
                        tx.setPosition(leash, rect.left.toFloat(), rect.top.toFloat())
                            .setWindowCrop(leash, rect.width(), rect.height())
                            .show(leash)
                        windowDecor.updateResizeVeil(tx, rect)
                    }
                    start()
                }
        return true
    }

    override fun handleRequest(
        transition: IBinder,
        request: TransitionRequestInfo
    ): WindowContainerTransaction? {
        return null
    }

    private fun findRelevantChange(info: TransitionInfo): TransitionInfo.Change {
        val matchingChanges =
            info.changes.filter { c ->
                !isWallpaper(c) && isValidTaskChange(c) && c.mode == TRANSIT_CHANGE
            }
        if (matchingChanges.size != 1) {
            throw IllegalStateException(
                "Expected 1 relevant change but found: ${matchingChanges.size}"
            )
        }
        return matchingChanges.first()
    }

    private fun isWallpaper(change: TransitionInfo.Change): Boolean {
        return (change.flags and TransitionInfo.FLAG_IS_WALLPAPER) != 0
    }

    private fun isValidTaskChange(change: TransitionInfo.Change): Boolean {
        return change.taskInfo != null && change.taskInfo?.taskId != -1
    }

    companion object {
        private const val RESIZE_DURATION_MS = 300L
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -161,6 +161,10 @@ public class Transitions implements RemoteCallable<Transitions>,
    public static final int TRANSIT_CANCEL_ENTERING_DESKTOP_MODE =
            WindowManager.TRANSIT_FIRST_CUSTOM + 13;

    /** Transition type to animate the toggle resize between the max and default desktop sizes. */
    public static final int TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE =
            WindowManager.TRANSIT_FIRST_CUSTOM + 14;

    private final WindowOrganizer mOrganizer;
    private final Context mContext;
    private final ShellExecutor mMainExecutor;
+3 −1
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ import android.window.TransitionInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;

import androidx.annotation.Nullable;

import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
@@ -258,7 +260,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
         * @return {@code true} if a drag is happening; or {@code false} if it is not
         */
        @Override
        public boolean handleMotionEvent(MotionEvent e) {
        public boolean handleMotionEvent(@Nullable View v, MotionEvent e) {
            final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
            if (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
                return false;
Loading