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

Commit 88568848 authored by Jeremy Sim's avatar Jeremy Sim Committed by Android (Google) Code Review
Browse files

Merge changes from topic "dim-layers-in-recents" into main

* changes:
  Flexible 2-app split: Dimming (part 2)
  Flexible 2-app split: Dimming (part 1)
parents 7d5745c2 84443907
Loading
Loading
Loading
Loading
+42 −3
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.view.RemoteAnimationTarget.MODE_CHANGING;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.LayoutParams.LAST_SYSTEM_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
@@ -55,9 +56,15 @@ import java.util.function.Predicate;
public class TransitionUtil {
    /** Flag applied to a transition change to identify it as a divider bar for animation. */
    public static final int FLAG_IS_DIVIDER_BAR = FLAG_FIRST_CUSTOM;
    public static final int FLAG_IS_DIM_LAYER = FLAG_FIRST_CUSTOM << 1;

    /** Flag applied to a transition change to identify it as a desktop wallpaper activity. */
    public static final int FLAG_IS_DESKTOP_WALLPAPER_ACTIVITY = FLAG_FIRST_CUSTOM << 1;
    public static final int FLAG_IS_DESKTOP_WALLPAPER_ACTIVITY = FLAG_FIRST_CUSTOM << 2;

    /**
     * Applied to a {@link RemoteAnimationTarget} to identify dim layers for animation in Launcher.
     */
    public static final int TYPE_SPLIT_SCREEN_DIM_LAYER = LAST_SYSTEM_WINDOW + 1;

    /** @return true if the transition was triggered by opening something vs closing something */
    public static boolean isOpeningType(@WindowManager.TransitionType int type) {
@@ -117,6 +124,11 @@ public class TransitionUtil {
        return isNonApp(change) && change.hasFlags(FLAG_IS_DIVIDER_BAR);
    }

    /** Returns `true` if `change` is an app's dim layer. */
    public static boolean isDimLayer(TransitionInfo.Change change) {
        return isNonApp(change) && change.hasFlags(FLAG_IS_DIM_LAYER);
    }

    /** Returns `true` if `change` is only re-ordering. */
    public static boolean isOrderOnly(TransitionInfo.Change change) {
        return change.getMode() == TRANSIT_CHANGE
@@ -231,6 +243,14 @@ public class TransitionUtil {
            t.setLayer(leash, Integer.MAX_VALUE);
            return;
        }
        if (isDimLayer(change)) {
            // When a dim layer gets reparented onto the transition root, we need to zero out its
            // position so that it's in line with everything else on the transition root. Also,
            // we need to set a crop because we don't want it applying MATCH_PARENT on the whole
            // root surface.
            t.setPosition(leash, 0, 0);
            t.setCrop(leash, change.getEndAbsBounds());
        }

        // Put all the OPEN/SHOW on top
        if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
@@ -284,14 +304,19 @@ public class TransitionUtil {
        // Copied Transitions setup code (which expects bottom-to-top order, so we swap here)
        setupLeash(leashSurface, change, info.getChanges().size() - order, info, t);
        t.reparent(change.getLeash(), leashSurface);
        if (!isDimLayer(change)) {
            // Most leashes going onto the transition root should have their alpha set here to make
            // them visible. But dim layers should be left untouched (their alpha value is their
            // actual dim value).
            t.setAlpha(change.getLeash(), 1.0f);
        t.show(change.getLeash());
        }
        if (!isDividerBar(change)) {
            // For divider, don't modify its inner leash position when creating the outer leash
            // for the transition. In case the position being wrong after the transition finished.
            t.setPosition(change.getLeash(), 0, 0);
        }
        t.setLayer(change.getLeash(), 0);
        t.show(change.getLeash());
        return leashSurface;
    }

@@ -333,6 +358,9 @@ public class TransitionUtil {
        if (isDividerBar(change)) {
            return getDividerTarget(change, leash);
        }
        if (isDimLayer(change)) {
            return getDimLayerTarget(change, leash);
        }

        int taskId;
        boolean isNotInRecents;
@@ -439,6 +467,17 @@ public class TransitionUtil {
                TYPE_DOCK_DIVIDER);
    }

    private static RemoteAnimationTarget getDimLayerTarget(TransitionInfo.Change change,
            SurfaceControl leash) {
        return new RemoteAnimationTarget(-1 /* taskId */, newModeToLegacyMode(change.getMode()),
                leash, false /* isTranslucent */, null /* clipRect */,
                null /* contentInsets */, Integer.MAX_VALUE /* prefixOrderIndex */,
                new android.graphics.Point(0, 0) /* position */, change.getStartAbsBounds(),
                change.getStartAbsBounds(), new WindowConfiguration(), true, null /* startLeash */,
                null /* startBounds */, null /* taskInfo */, false /* allowEnterPip */,
                TYPE_SPLIT_SCREEN_DIM_LAYER);
    }

    /**
     * Finds the "correct" root idx for a change. The change's end display is prioritized, then
     * the start display. If there is no display, it will fallback on the 0th root in the
+11 −0
Original line number Diff line number Diff line
@@ -93,9 +93,20 @@ public class Interpolators {
    public static final PathInterpolator SLOWDOWN_INTERPOLATOR =
            new PathInterpolator(0.5f, 1f, 0.5f, 1f);

    /**
     * An interpolator used for dimming a task as it travels offscreen, or towards a distant dismiss
     * point. A sharp rise, followed by a steady middle, and ending with another sharp rise.
     */
    public static final PathInterpolator DIM_INTERPOLATOR =
            new PathInterpolator(.23f, .87f, .52f, -0.11f);

    /**
     * An interpolator used for dimming a task very quickly. Roughly approximates one of the "sharp
     * rises" of {@link #DIM_INTERPOLATOR}.
     */
    public static final PathInterpolator FAST_DIM_INTERPOLATOR =
            new PathInterpolator(0.23f, 0.87f, 0.83f, 0.83f);

    /**
     * Use this interpolator for animating progress values coming from the back callback to get
     * the predictive-back-typical decelerate motion.
+1 −0
Original line number Diff line number Diff line
@@ -262,6 +262,7 @@ public class SplitScreenConstants {

    /** Flag applied to a transition change to identify it as a divider bar for animation. */
    public static final int FLAG_IS_DIVIDER_BAR = TransitionUtil.FLAG_IS_DIVIDER_BAR;
    public static final int FLAG_IS_DIM_LAYER = TransitionUtil.FLAG_IS_DIM_LAYER;

    public static final String splitPositionToString(@SplitPosition int pos) {
        switch (pos) {
+39 −0
Original line number Diff line number Diff line
/*
 * 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.common.split;

import android.graphics.Point;
import android.graphics.Rect;

/**
 * Calculation class, used when
 * {@link com.android.wm.shell.common.split.SplitLayout#PARALLAX_ALIGN_CENTER} is the desired
 * parallax effect.
 */
public class CenterParallaxSpec implements ParallaxSpec {
    @Override
    public void getParallax(Point retreatingOut, Point advancingOut, int position,
            DividerSnapAlgorithm snapAlgorithm, boolean isLeftRightSplit, Rect displayBounds,
            Rect retreatingSurface, Rect retreatingContent, Rect advancingSurface,
            Rect advancingContent, int dimmingSide, boolean topLeftShrink) {
        if (isLeftRightSplit) {
            retreatingOut.x = (retreatingSurface.width() - retreatingContent.width()) / 2;
        } else {
            retreatingOut.y = (retreatingSurface.height() - retreatingContent.height()) / 2;
        }
    }
}
+75 −0
Original line number Diff line number Diff line
/*
 * 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.common.split;

import static android.view.WindowManager.DOCKED_INVALID;

import static com.android.wm.shell.shared.animation.Interpolators.SLOWDOWN_INTERPOLATOR;

import android.graphics.Point;
import android.graphics.Rect;
import android.view.WindowManager;

/**
 * Calculation class, used when
 * {@link com.android.wm.shell.common.split.SplitLayout#PARALLAX_DISMISSING} is the desired parallax
 * effect.
 */
public class DismissingParallaxSpec implements ParallaxSpec {
    @Override
    public void getParallax(Point retreatingOut, Point advancingOut, int position,
            DividerSnapAlgorithm snapAlgorithm, boolean isLeftRightSplit, Rect displayBounds,
            Rect retreatingSurface, Rect retreatingContent, Rect advancingSurface,
            Rect advancingContent, int dimmingSide, boolean topLeftShrink) {
        if (dimmingSide == DOCKED_INVALID) {
            return;
        }

        float progressTowardScreenEdge =
                Math.max(0, Math.min(snapAlgorithm.calculateDismissingFraction(position), 1f));
        int totalDismissingDistance = 0;
        if (position < snapAlgorithm.getFirstSplitTarget().getPosition()) {
            totalDismissingDistance = snapAlgorithm.getDismissStartTarget().getPosition()
                    - snapAlgorithm.getFirstSplitTarget().getPosition();
        } else if (position > snapAlgorithm.getLastSplitTarget().getPosition()) {
            totalDismissingDistance = snapAlgorithm.getLastSplitTarget().getPosition()
                    - snapAlgorithm.getDismissEndTarget().getPosition();
        }

        float parallaxFraction =
                calculateParallaxDismissingFraction(progressTowardScreenEdge, dimmingSide);
        if (isLeftRightSplit) {
            retreatingOut.x = (int) (parallaxFraction * totalDismissingDistance);
        } else {
            retreatingOut.y = (int) (parallaxFraction * totalDismissingDistance);
        }
    }

    /**
     * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
     * slowing down parallax effect
     */
    private float calculateParallaxDismissingFraction(float fraction, int dockSide) {
        float result = SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;

        // Less parallax at the top, just because.
        if (dockSide == WindowManager.DOCKED_TOP) {
            result /= 2f;
        }
        return result;
    }
}
Loading