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

Commit 1b73388e authored by Marzia Favaro's avatar Marzia Favaro Committed by Android (Google) Code Review
Browse files

Merge "Add interface to store compatibility between handlers and transitions" into main

parents 8199cb55 56fb3d89
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -550,6 +550,13 @@ flag {
    }
}

flag {
    name: "enable_handlers_debugging_mode"
    namespace: "windowing_frontend"
    description: "collect data on handlers that did or did not play"
    bug: "402454136"
}

flag {
    name: "enable_multidisplay_trackpad_back_gesture"
    namespace: "lse_desktop_experience"
+254 −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.transition;

import static com.android.wm.shell.transition.Transitions.transitTypeToString;

import android.annotation.NonNull;
import android.os.IBinder;
import android.util.ArrayMap;
import android.view.WindowManager;
import android.window.TransitionInfo;

import androidx.annotation.IntDef;

import java.util.ArrayList;

public class TransitionDispatchState {
    public static final int NONE = 0;
    // Flag-related errors
    public static final int LOST_RELEVANT_FLAG = 1;
    public static final int CAPTURED_UNRELATED_FLAG = 2;
    // Change-related errors
    public static final int LOST_RELEVANT_CHANGE = 3;
    public static final int CAPTURED_UNRELATED_CHANGE = 4;

    @IntDef(
            value = {
                NONE,
                LOST_RELEVANT_FLAG,
                CAPTURED_UNRELATED_FLAG,
                LOST_RELEVANT_CHANGE,
                CAPTURED_UNRELATED_CHANGE,
            })
    public @interface ErrorCode {}

    static String toString(@ErrorCode int errorCode) {
        return switch (errorCode) {
            case NONE -> "NONE";
            case LOST_RELEVANT_FLAG -> "LOST_RELEVANT_FLAG";
            case CAPTURED_UNRELATED_FLAG -> "CAPTURED_UNRELATED_FLAG";
            case LOST_RELEVANT_CHANGE -> "LOST_RELEVANT_CHANGE";
            case CAPTURED_UNRELATED_CHANGE -> "CAPTURED_UNRELATED_CHANGE";
            default -> "UNKNOWN";
        };
    }

    final ArrayMap<Transitions.TransitionHandler, HandlerData>
            mHandlersData = new ArrayMap<>();
    final IBinder mTransition;
    public final TransitionInfo mInfo;

    private static DummyTransitionDispatchState sDummyInstance;

    private TransitionDispatchState() {
        // Can only be used only by dummy instance.
        mTransition = null;
        mInfo = null;
    }

    public TransitionDispatchState(@NonNull IBinder transition, @NonNull TransitionInfo info) {
        mTransition = transition;
        mInfo = info;
    }

    /**
     * @return a dummy instance of {@link TransitionDispatchState} that does nothing.
     */
    public static TransitionDispatchState getDummyInstance() {
        if (sDummyInstance == null) {
            sDummyInstance = new DummyTransitionDispatchState();
        }
        return sDummyInstance;
    }

    /**
     * @param handler the handler that is interested in this transition.
     * @param change  If the handler has consumed the transition, this is a change that has not been
     *                animated.
     *                If the handler has not consumed it, this is a change that the handler would
     *                have been interested in animating.
     * @param errorCode an error code to identify the error type.
     */
    public void addError(@NonNull Transitions.TransitionHandler handler,
                         @NonNull TransitionInfo.Change change, @ErrorCode int errorCode) {
        HandlerData handlerData = getDataOrCreate(handler);
        HandlerData.Error error =
                new HandlerData.Error(change, errorCode);
        handlerData.mErrors.add(error);
    }

    /**
     * @param handler the handler that is interested in this transition.
     * @param flag    a flag that the handler finds relevant, either because it should have been
     *                handled by handler (and it didn't) or because it was not relevant for handling
     *                the transition (which was played by handler).
     * @param errorCode an error code to identify the error type.
     */
    public void addError(@NonNull Transitions.TransitionHandler handler,
                         @WindowManager.TransitionFlags int flag, @ErrorCode int errorCode) {
        HandlerData handlerData = getDataOrCreate(handler);
        HandlerData.Error error =
                new HandlerData.Error(flag, errorCode);
        handlerData.mErrors.add(error);
    }

    /**
     * Sets that {@param handler} has played at least part of this transition.
     */
    public void setHasPlayed(@NonNull Transitions.TransitionHandler handler) {
        HandlerData handlerData = getDataOrCreate(handler);
        handlerData.mHasPlayed = true;
    }

    /**
     * @return true if {@param handler} has played at least part of this transition.
     */
    public boolean hasPlayed(@NonNull Transitions.TransitionHandler handler) {
        HandlerData handlerData = mHandlersData.get(handler);
        if (handlerData == null) {
            return false;
        }
        return handlerData.mHasPlayed;
    }

    /**
     * @return true if {@param handler} has found problems with the handling of this transition.
     */
    public boolean hasErrors(@NonNull Transitions.TransitionHandler handler) {
        HandlerData handlerData = mHandlersData.get(handler);
        if (handlerData == null) {
            return false;
        }
        return !handlerData.mErrors.isEmpty();
    }

    /**
     * Report all the errors found by the handlers to an atom.
     */
    public void reportWarnings() {
        throw new UnsupportedOperationException("Not implemented");
    }

    /**
     * @return a string containing the analyzed handlers and the information they collected.
     */
    public String getDebugInfo() {
        StringBuilder sb = new StringBuilder();
        sb.append("Transition #").append(mInfo.getDebugId()).append(": {");
        for (int i = 0; i < mHandlersData.size(); i++) {
            HandlerData handlerData = mHandlersData.valueAt(i);
            if (!handlerData.mErrors.isEmpty() || handlerData.mHasPlayed) {
                // Handler + collected info
                sb.append("\n    ");
                sb.append(handlerData.mHandler.getClass().getSimpleName()).append(": [");
                sb.append("hasPlayed=").append(handlerData.mHasPlayed);
                for (int j = 0; j < handlerData.mErrors.size(); j++) {
                    HandlerData.Error err = handlerData.mErrors.get(j);
                    sb.append(" Errors={");
                    if (err.mChange != null) {
                        sb.append("ChangeError(").append(toString(err.mErrorCode));
                        sb.append(" -- ").append(err.mChange);
                        sb.append("), ");
                    } else if (err.mTransitFlag != 0) {
                        sb.append("FlagError(").append(toString(err.mErrorCode));
                        sb.append(" -- ").append(transitTypeToString(err.mTransitFlag));
                        sb.append("}, ");
                    }
                }
                sb.append("]");
            }
        }
        sb.append("\n}");
        return sb.toString();
    }

    private HandlerData getDataOrCreate(
            @NonNull Transitions.TransitionHandler handler) {
        HandlerData handlerData = mHandlersData.get(handler);
        if (handlerData != null) return handlerData;
        handlerData = new HandlerData(handler);
        mHandlersData.put(handler, handlerData);
        return handlerData;
    }


    /**
     * HandlerData collects errors and information relative to a handler
     * in relation to a transition.
     */
    static class HandlerData {
        /**
         * Collects information about errors found by a handler
         */
        static class Error {
            final TransitionInfo.Change mChange;
            final @WindowManager.TransitionFlags int mTransitFlag;
            final @ErrorCode int mErrorCode;

            Error(int flag, @ErrorCode int errorCode) {
                mTransitFlag = flag;
                mErrorCode = errorCode;
                mChange = null;
            }

            Error(@NonNull TransitionInfo.Change change, @ErrorCode int errorCode) {
                mChange = change;
                mErrorCode = errorCode;
                mTransitFlag = 0;
            }
        }

        final Transitions.TransitionHandler mHandler;
        final ArrayList<Error> mErrors = new ArrayList<>();
        boolean mHasPlayed = false;

        HandlerData(Transitions.TransitionHandler handler) {
            mHandler = handler;
        }
    }

    /**
     * Dummy implementation of {@link TransitionDispatchState} that does nothing.
     * This is used temporary until Transitions.TransitionHandler.startAnimation(...) without
     * TransitionDispatchState is deprecated.
     */
    private static class DummyTransitionDispatchState extends TransitionDispatchState {
        @Override
        public void addError(@NonNull Transitions.TransitionHandler handler,
                             @NonNull TransitionInfo.Change change,
                             @ErrorCode int errorCode) {}

        @Override
        public void addError(@NonNull Transitions.TransitionHandler handler,
                             @WindowManager.TransitionFlags int flag,
                             @ErrorCode int errorCode) {}

        @Override
        public void setHasPlayed(@NonNull Transitions.TransitionHandler handler) {}
    }
}
+20 −0
Original line number Diff line number Diff line
@@ -1438,6 +1438,26 @@ public class Transitions implements RemoteCallable<Transitions>,
                @NonNull SurfaceControl.Transaction finishTransaction,
                @NonNull TransitionFinishCallback finishCallback);

        /**
         * Like {@link #startAnimation(IBinder, TransitionInfo, SurfaceControl.Transaction,
         * SurfaceControl.Transaction, TransitionFinishCallback)} when {@param info} is not null.
         * When {@param info} is null, startAnimation won't do any active animation, but will just
         * collect information about the compatibility of the handler and the transition in
         * {@param dispatchState}.
         */
        default boolean startAnimation(@NonNull IBinder transition,
                                       @Nullable TransitionInfo consumableInfo,
                                       @NonNull TransitionDispatchState dispatchState,
                                       @NonNull SurfaceControl.Transaction startTransaction,
                                       @NonNull SurfaceControl.Transaction finishTransaction,
                                       @NonNull TransitionFinishCallback finishCallback) {
            if (consumableInfo != null) {
                return startAnimation(transition, consumableInfo, startTransaction,
                        finishTransaction, finishCallback);
            }
            return false;
        }

        /**
         * See {@link #mergeAnimation(IBinder, TransitionInfo, SurfaceControl.Transaction, SurfaceControl.Transaction, IBinder, TransitionFinishCallback)}
         *