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

Commit d08aeac5 authored by Eghosa Ewansiha-Vlachavas's avatar Eghosa Ewansiha-Vlachavas
Browse files

Refactor DesktopModeLaunchParamsModifer

Remove initial bounds calculations and desktop windowing state checkers
into seperate classes.

Flag: NONE (refactoring)
Test: atest WmTests:DesktopModeLaunchParamsModifierTests
Fixes: 352737356
Change-Id: I65ed77133a9e477a2ee76bf34c13535064a7d825
parent 5bf92046
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -233,7 +233,7 @@ import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_F
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
import static com.android.server.wm.ActivityTaskManagerService.getInputDispatchingTimeoutMillisLocked;
import static com.android.server.wm.DesktopModeLaunchParamsModifier.canEnterDesktopMode;
import static com.android.server.wm.DesktopModeHelper.canEnterDesktopMode;
import static com.android.server.wm.IdentifierProto.HASH_CODE;
import static com.android.server.wm.IdentifierProto.TITLE;
import static com.android.server.wm.IdentifierProto.USER_ID;
+1 −1
Original line number Diff line number Diff line
@@ -47,7 +47,7 @@ class AppCompatCameraPolicy {
        final boolean needsDisplayRotationCompatPolicy =
                wmService.mLetterboxConfiguration.isCameraCompatTreatmentEnabledAtBuildTime();
        final boolean needsCameraCompatFreeformPolicy = Flags.cameraCompatForFreeform()
                && DesktopModeLaunchParamsModifier.canEnterDesktopMode(wmService.mContext);
                && DesktopModeHelper.canEnterDesktopMode(wmService.mContext);
        if (needsDisplayRotationCompatPolicy || needsCameraCompatFreeformPolicy) {
            mCameraStateMonitor = new CameraStateMonitor(displayContent, wmService.mH);
            mActivityRefresher = new ActivityRefresher(wmService, wmService.mH);
+99 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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.server.wm;

import static com.android.server.wm.LaunchParamsUtil.applyLayoutGravity;
import static com.android.server.wm.LaunchParamsUtil.calculateLayoutBounds;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.content.pm.ActivityInfo;
import android.graphics.Rect;
import android.os.SystemProperties;
import android.util.Size;
import android.view.Gravity;

import java.util.function.Consumer;

/**
 * Calculates the value of the {@link LaunchParamsController.LaunchParams} bounds for the
 * {@link DesktopModeLaunchParamsModifier}.
 */
public final class DesktopModeBoundsCalculator {

    public static final float DESKTOP_MODE_INITIAL_BOUNDS_SCALE = SystemProperties
            .getInt("persist.wm.debug.desktop_mode_initial_bounds_scale", 75) / 100f;

    /**
     * Updates launch bounds for an activity with respect to its activity options, window layout,
     * android manifest and task configuration.
     */
    static void updateInitialBounds(@NonNull Task task, @Nullable ActivityInfo.WindowLayout layout,
            @Nullable ActivityRecord activity, @Nullable ActivityOptions options,
            @NonNull Rect outBounds, @NonNull Consumer<String> logger) {
        // Use stable frame instead of raw frame to avoid launching freeform windows on top of
        // stable insets, which usually are system widgets such as sysbar & navbar.
        final TaskDisplayArea displayArea = task.getDisplayArea();
        final Rect screenBounds = displayArea.getBounds();
        final Rect stableBounds = new Rect();
        displayArea.getStableRect(stableBounds);
        final int desiredWidth = (int) (stableBounds.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
        final int desiredHeight = (int) (stableBounds.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);

        if (options != null && options.getLaunchBounds() != null) {
            outBounds.set(options.getLaunchBounds());
            logger.accept("inherit-from-options=" + outBounds);
        } else if (layout != null) {
            final int verticalGravity = layout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
            final int horizontalGravity = layout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
            if (layout.hasSpecifiedSize()) {
                calculateLayoutBounds(stableBounds, layout, outBounds,
                        new Size(desiredWidth, desiredHeight));
                applyLayoutGravity(verticalGravity, horizontalGravity, outBounds,
                        stableBounds);
                logger.accept("layout specifies sizes, inheriting size and applying gravity");
            } else if (verticalGravity > 0 || horizontalGravity > 0) {
                calculateAndCentreInitialBounds(outBounds, screenBounds);
                applyLayoutGravity(verticalGravity, horizontalGravity, outBounds,
                        stableBounds);
                logger.accept("layout specifies gravity, applying desired bounds and gravity");
            }
        } else {
            calculateAndCentreInitialBounds(outBounds, screenBounds);
            logger.accept("layout not specified, applying desired bounds");
        }
    }

    /**
     * Calculates the initial height and width of a task in desktop mode and centers it within the
     * window bounds.
     */
    private static void calculateAndCentreInitialBounds(@NonNull Rect outBounds,
            @NonNull Rect screenBounds) {
        // TODO(b/319819547): Account for app constraints so apps do not become letterboxed
        // The desired dimensions that a fully resizable window should take when initially entering
        // desktop mode. Calculated as a percentage of the available display area as defined by the
        // DESKTOP_MODE_INITIAL_BOUNDS_SCALE.
        final int desiredWidth = (int) (screenBounds.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
        final int desiredHeight = (int) (screenBounds.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
        outBounds.right = desiredWidth;
        outBounds.bottom = desiredHeight;
        outBounds.offset(screenBounds.centerX() - outBounds.centerX(),
                screenBounds.centerY() - outBounds.centerY());
    }
}
+66 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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.server.wm;

import android.annotation.NonNull;
import android.content.Context;
import android.os.SystemProperties;

import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.window.flags.Flags;

/**
 * Constants for desktop mode feature
 */
public final class DesktopModeHelper {
    /**
     * Flag to indicate whether to restrict desktop mode to supported devices.
     */
    private static final boolean ENFORCE_DEVICE_RESTRICTIONS = SystemProperties.getBoolean(
            "persist.wm.debug.desktop_mode_enforce_device_restrictions", true);

    /** Whether desktop mode is enabled. */
    static boolean isDesktopModeEnabled() {
        return Flags.enableDesktopWindowingMode();
    }

    /**
     * Return {@code true} if desktop mode should be restricted to supported devices.
     */
    @VisibleForTesting
    static boolean shouldEnforceDeviceRestrictions() {
        return ENFORCE_DEVICE_RESTRICTIONS;
    }

    /**
     * Return {@code true} if the current device supports desktop mode.
     */
    // TODO(b/337819319): use a companion object instead.
    @VisibleForTesting
    static boolean isDesktopModeSupported(@NonNull Context context) {
        return context.getResources().getBoolean(R.bool.config_isDesktopModeSupported);
    }

    /**
     * Return {@code true} if desktop mode can be entered on the current device.
     */
    static boolean canEnterDesktopMode(@NonNull Context context) {
        return isDesktopModeEnabled()
                && (!shouldEnforceDeviceRestrictions() || isDesktopModeSupported(context));
    }
}
+9 −93
Original line number Diff line number Diff line
@@ -18,28 +18,21 @@ package com.android.server.wm;

import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.LaunchParamsUtil.applyLayoutGravity;
import static com.android.server.wm.LaunchParamsUtil.calculateLayoutBounds;
import static com.android.server.wm.DesktopModeHelper.canEnterDesktopMode;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Rect;
import android.os.SystemProperties;
import android.util.Size;
import android.util.Slog;
import android.view.Gravity;

import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
import com.android.window.flags.Flags;
/**
 * The class that defines default launch params for tasks in desktop mode
 */
public class DesktopModeLaunchParamsModifier implements LaunchParamsModifier {
class DesktopModeLaunchParamsModifier implements LaunchParamsModifier {

    private static final String TAG =
            TAG_WITH_CLASS_NAME ? "DesktopModeLaunchParamsModifier" : TAG_ATM;
@@ -67,8 +60,8 @@ public class DesktopModeLaunchParamsModifier implements LaunchParamsModifier {
    public int onCalculate(@Nullable Task task, @Nullable ActivityInfo.WindowLayout layout,
            @Nullable ActivityRecord activity, @Nullable ActivityRecord source,
            @Nullable ActivityOptions options, @Nullable ActivityStarter.Request request, int phase,
            LaunchParamsController.LaunchParams currentParams,
            LaunchParamsController.LaunchParams outParams) {
            @NonNull LaunchParamsController.LaunchParams currentParams,
            @NonNull LaunchParamsController.LaunchParams outParams) {

        initLogBuilder(task, activity);
        int result = calculate(task, layout, activity, source, options, request, phase,
@@ -80,15 +73,15 @@ public class DesktopModeLaunchParamsModifier implements LaunchParamsModifier {
    private int calculate(@Nullable Task task, @Nullable ActivityInfo.WindowLayout layout,
            @Nullable ActivityRecord activity, @Nullable ActivityRecord source,
            @Nullable ActivityOptions options, @Nullable ActivityStarter.Request request, int phase,
            LaunchParamsController.LaunchParams currentParams,
            LaunchParamsController.LaunchParams outParams) {
            @NonNull LaunchParamsController.LaunchParams currentParams,
            @NonNull LaunchParamsController.LaunchParams outParams) {

        if (!canEnterDesktopMode(mContext)) {
            appendLog("desktop mode is not enabled, skipping");
            return RESULT_SKIP;
        }

        if (task == null) {
        if (task == null || !task.isAttached()) {
            appendLog("task null, skipping");
            return RESULT_SKIP;
        }
@@ -123,59 +116,12 @@ public class DesktopModeLaunchParamsModifier implements LaunchParamsModifier {
            return RESULT_SKIP;
        }

        // Use stable frame instead of raw frame to avoid launching freeform windows on top of
        // stable insets, which usually are system widgets such as sysbar & navbar.
        final Rect stableBounds = new Rect();
        task.getDisplayArea().getStableRect(stableBounds);
        final int desiredWidth = (int) (stableBounds.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
        final int desiredHeight = (int) (stableBounds.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);

        if (options != null && options.getLaunchBounds() != null) {
            outParams.mBounds.set(options.getLaunchBounds());
            appendLog("inherit-from-options=" + outParams.mBounds);
        } else if (layout != null) {
            final int verticalGravity = layout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
            final int horizontalGravity = layout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
            if (layout.hasSpecifiedSize()) {
                calculateLayoutBounds(stableBounds, layout, outParams.mBounds,
                        new Size(desiredWidth, desiredHeight));
                applyLayoutGravity(verticalGravity, horizontalGravity, outParams.mBounds,
                        stableBounds);
                appendLog("layout specifies sizes, inheriting size and applying gravity");
            } else if (verticalGravity > 0 || horizontalGravity > 0) {
                calculateAndCentreInitialBounds(task, outParams);
                applyLayoutGravity(verticalGravity, horizontalGravity, outParams.mBounds,
                        stableBounds);
                appendLog("layout specifies gravity, applying desired bounds and gravity");
            }
        } else {
            calculateAndCentreInitialBounds(task, outParams);
            appendLog("layout not specified, applying desired bounds");
        }

        DesktopModeBoundsCalculator.updateInitialBounds(task, layout, activity, options,
                outParams.mBounds, this::appendLog);
        appendLog("final desktop mode task bounds set to %s", outParams.mBounds);
        return RESULT_CONTINUE;
    }

    /**
     * Calculates the initial height and width of a task in desktop mode and centers it within the
     * window bounds.
     */
    private void calculateAndCentreInitialBounds(Task task,
            LaunchParamsController.LaunchParams outParams) {
        // TODO(b/319819547): Account for app constraints so apps do not become letterboxed
        final Rect screenBounds = task.getDisplayArea().getBounds();
        // The desired dimensions that a fully resizable window should take when initially entering
        // desktop mode. Calculated as a percentage of the available display area as defined by the
        // DESKTOP_MODE_INITIAL_BOUNDS_SCALE.
        final int desiredWidth = (int) (screenBounds.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
        final int desiredHeight = (int) (screenBounds.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
        outParams.mBounds.right = desiredWidth;
        outParams.mBounds.bottom = desiredHeight;
        outParams.mBounds.offset(screenBounds.centerX() - outParams.mBounds.centerX(),
                screenBounds.centerY() - outParams.mBounds.centerY());
    }

    private void initLogBuilder(Task task, ActivityRecord activity) {
        if (DEBUG) {
            mLogBuilder = new StringBuilder(
@@ -190,34 +136,4 @@ public class DesktopModeLaunchParamsModifier implements LaunchParamsModifier {
    private void outputLog() {
        if (DEBUG) Slog.d(TAG, mLogBuilder.toString());
    }

    /** Whether desktop mode is enabled. */
    static boolean isDesktopModeEnabled() {
        return Flags.enableDesktopWindowingMode();
    }

    /**
     * Return {@code true} if desktop mode should be restricted to supported devices.
     */
    @VisibleForTesting
    static boolean enforceDeviceRestrictions() {
        return ENFORCE_DEVICE_RESTRICTIONS;
    }

    /**
     * Return {@code true} if the current device supports desktop mode.
     */
    // TODO(b/337819319): use a companion object instead.
    @VisibleForTesting
    static boolean isDesktopModeSupported(@NonNull Context context) {
        return context.getResources().getBoolean(R.bool.config_isDesktopModeSupported);
    }

    /**
     * Return {@code true} if desktop mode can be entered on the current device.
     */
    static boolean canEnterDesktopMode(@NonNull Context context) {
        return isDesktopModeEnabled()
                && (!enforceDeviceRestrictions() || isDesktopModeSupported(context));
    }
}
Loading