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

Commit 16b78301 authored by Garfield Tan's avatar Garfield Tan Committed by Android (Google) Code Review
Browse files

Merge "Put window decors at one place" into tm-qpr-dev

parents 9c2072fa 73166e71
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -292,17 +292,17 @@ public abstract class WMShellBaseModule {
    // Workaround for dynamic overriding with a default implementation, see {@link DynamicOverride}
    @BindsOptionalOf
    @DynamicOverride
    abstract FullscreenTaskListener<?> optionalFullscreenTaskListener();
    abstract FullscreenTaskListener optionalFullscreenTaskListener();

    @WMSingleton
    @Provides
    static FullscreenTaskListener<?> provideFullscreenTaskListener(
            @DynamicOverride Optional<FullscreenTaskListener<?>> fullscreenTaskListener,
    static FullscreenTaskListener provideFullscreenTaskListener(
            @DynamicOverride Optional<FullscreenTaskListener> fullscreenTaskListener,
            ShellInit shellInit,
            ShellTaskOrganizer shellTaskOrganizer,
            SyncTransactionQueue syncQueue,
            Optional<RecentTasksController> recentTasksOptional,
            Optional<WindowDecorViewModel<?>> windowDecorViewModelOptional) {
            Optional<WindowDecorViewModel> windowDecorViewModelOptional) {
        if (fullscreenTaskListener.isPresent()) {
            return fullscreenTaskListener.get();
        } else {
@@ -316,7 +316,7 @@ public abstract class WMShellBaseModule {
    //

    @BindsOptionalOf
    abstract WindowDecorViewModel<?> optionalWindowDecorViewModel();
    abstract WindowDecorViewModel optionalWindowDecorViewModel();

    //
    // Unfold transition
@@ -768,7 +768,7 @@ public abstract class WMShellBaseModule {
            Optional<SplitScreenController> splitScreenOptional,
            Optional<Pip> pipOptional,
            Optional<PipTouchHandler> pipTouchHandlerOptional,
            FullscreenTaskListener<?> fullscreenTaskListener,
            FullscreenTaskListener fullscreenTaskListener,
            Optional<UnfoldAnimationController> unfoldAnimationController,
            Optional<UnfoldTransitionHandler> unfoldTransitionHandler,
            Optional<FreeformComponents> freeformComponents,
+8 −10
Original line number Diff line number Diff line
@@ -55,7 +55,6 @@ import com.android.wm.shell.freeform.FreeformComponents;
import com.android.wm.shell.freeform.FreeformTaskListener;
import com.android.wm.shell.freeform.FreeformTaskTransitionHandler;
import com.android.wm.shell.freeform.FreeformTaskTransitionObserver;
import com.android.wm.shell.fullscreen.FullscreenTaskListener;
import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
@@ -183,7 +182,7 @@ public abstract class WMShellModule {

    @WMSingleton
    @Provides
    static WindowDecorViewModel<?> provideWindowDecorViewModel(
    static WindowDecorViewModel provideWindowDecorViewModel(
            Context context,
            @ShellMainThread Handler mainHandler,
            @ShellMainThread Choreographer mainChoreographer,
@@ -209,7 +208,7 @@ public abstract class WMShellModule {
    @Provides
    @DynamicOverride
    static FreeformComponents provideFreeformComponents(
            FreeformTaskListener<?> taskListener,
            FreeformTaskListener taskListener,
            FreeformTaskTransitionHandler transitionHandler,
            FreeformTaskTransitionObserver transitionObserver) {
        return new FreeformComponents(
@@ -218,18 +217,18 @@ public abstract class WMShellModule {

    @WMSingleton
    @Provides
    static FreeformTaskListener<?> provideFreeformTaskListener(
    static FreeformTaskListener provideFreeformTaskListener(
            Context context,
            ShellInit shellInit,
            ShellTaskOrganizer shellTaskOrganizer,
            Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
            WindowDecorViewModel<?> windowDecorViewModel) {
            WindowDecorViewModel windowDecorViewModel) {
        // TODO(b/238217847): Temporarily add this check here until we can remove the dynamic
        //                    override for this controller from the base module
        ShellInit init = FreeformComponents.isFreeformEnabled(context)
                ? shellInit
                : null;
        return new FreeformTaskListener<>(init, shellTaskOrganizer, desktopModeTaskRepository,
        return new FreeformTaskListener(init, shellTaskOrganizer, desktopModeTaskRepository,
                windowDecorViewModel);
    }

@@ -238,7 +237,7 @@ public abstract class WMShellModule {
    static FreeformTaskTransitionHandler provideFreeformTaskTransitionHandler(
            ShellInit shellInit,
            Transitions transitions,
            WindowDecorViewModel<?> windowDecorViewModel) {
            WindowDecorViewModel windowDecorViewModel) {
        return new FreeformTaskTransitionHandler(shellInit, transitions, windowDecorViewModel);
    }

@@ -248,10 +247,9 @@ public abstract class WMShellModule {
            Context context,
            ShellInit shellInit,
            Transitions transitions,
            FullscreenTaskListener<?> fullscreenTaskListener,
            FreeformTaskListener<?> freeformTaskListener) {
            WindowDecorViewModel windowDecorViewModel) {
        return new FreeformTaskTransitionObserver(
                context, shellInit, transitions, fullscreenTaskListener, freeformTaskListener);
                context, shellInit, transitions, windowDecorViewModel);
    }

    //
+18 −156
Original line number Diff line number Diff line
@@ -19,12 +19,8 @@ package com.android.wm.shell.freeform;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM;

import android.app.ActivityManager.RunningTaskInfo;
import android.util.Log;
import android.util.SparseArray;
import android.view.SurfaceControl;
import android.window.TransitionInfo;

import androidx.annotation.Nullable;

import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
@@ -41,31 +37,26 @@ import java.util.Optional;
/**
 * {@link ShellTaskOrganizer.TaskListener} for {@link
 * ShellTaskOrganizer#TASK_LISTENER_TYPE_FREEFORM}.
 *
 * @param <T> the type of window decoration instance
 */
public class FreeformTaskListener<T extends AutoCloseable>
        implements ShellTaskOrganizer.TaskListener {
public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener {
    private static final String TAG = "FreeformTaskListener";

    private final ShellTaskOrganizer mShellTaskOrganizer;
    private final Optional<DesktopModeTaskRepository> mDesktopModeTaskRepository;
    private final WindowDecorViewModel<T> mWindowDecorationViewModel;
    private final WindowDecorViewModel mWindowDecorationViewModel;

    private final SparseArray<State<T>> mTasks = new SparseArray<>();
    private final SparseArray<T> mWindowDecorOfVanishedTasks = new SparseArray<>();
    private final SparseArray<State> mTasks = new SparseArray<>();

    private static class State<T extends AutoCloseable> {
    private static class State {
        RunningTaskInfo mTaskInfo;
        SurfaceControl mLeash;
        T mWindowDecoration;
    }

    public FreeformTaskListener(
            ShellInit shellInit,
            ShellTaskOrganizer shellTaskOrganizer,
            Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
            WindowDecorViewModel<T> windowDecorationViewModel) {
            WindowDecorViewModel windowDecorationViewModel) {
        mShellTaskOrganizer = shellTaskOrganizer;
        mWindowDecorationViewModel = windowDecorationViewModel;
        mDesktopModeTaskRepository = desktopModeTaskRepository;
@@ -80,12 +71,17 @@ public class FreeformTaskListener<T extends AutoCloseable>

    @Override
    public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
        if (mTasks.get(taskInfo.taskId) != null) {
            throw new IllegalStateException("Task appeared more than once: #" + taskInfo.taskId);
        }
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Appeared: #%d",
                taskInfo.taskId);
        final State<T> state = createOrUpdateTaskState(taskInfo, leash);
        final State state = new State();
        state.mTaskInfo = taskInfo;
        state.mLeash = leash;
        mTasks.put(taskInfo.taskId, state);
        if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
            SurfaceControl.Transaction t = new SurfaceControl.Transaction();
            state.mWindowDecoration =
            mWindowDecorationViewModel.createWindowDecoration(taskInfo, leash, t, t);
            t.apply();
        }
@@ -97,28 +93,8 @@ public class FreeformTaskListener<T extends AutoCloseable>
        }
    }

    private State<T> createOrUpdateTaskState(RunningTaskInfo taskInfo, SurfaceControl leash) {
        State<T> state = mTasks.get(taskInfo.taskId);
        if (state != null) {
            updateTaskInfo(taskInfo);
            return state;
        }

        state = new State<>();
        state.mTaskInfo = taskInfo;
        state.mLeash = leash;
        mTasks.put(taskInfo.taskId, state);

        return state;
    }

    @Override
    public void onTaskVanished(RunningTaskInfo taskInfo) {
        final State<T> state = mTasks.get(taskInfo.taskId);
        if (state == null) {
            // This is possible if the transition happens before this method.
            return;
        }
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Vanished: #%d",
                taskInfo.taskId);
        mTasks.remove(taskInfo.taskId);
@@ -129,26 +105,18 @@ public class FreeformTaskListener<T extends AutoCloseable>
            mDesktopModeTaskRepository.ifPresent(it -> it.removeActiveTask(taskInfo.taskId));
        }

        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
            // Save window decorations of closing tasks so that we can hand them over to the
            // transition system if this method happens before the transition. In case where the
            // transition didn't happen, it'd be cleared when the next transition finished.
            if (state.mWindowDecoration != null) {
                mWindowDecorOfVanishedTasks.put(taskInfo.taskId, state.mWindowDecoration);
            }
            return;
        if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
            mWindowDecorationViewModel.destroyWindowDecoration(taskInfo);
        }
        releaseWindowDecor(state.mWindowDecoration);
    }

    @Override
    public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
        final State<T> state = updateTaskInfo(taskInfo);
        final State state = mTasks.get(taskInfo.taskId);
        state.mTaskInfo = taskInfo;
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Info Changed: #%d",
                taskInfo.taskId);
        if (state.mWindowDecoration != null) {
            mWindowDecorationViewModel.onTaskInfoChanged(state.mTaskInfo, state.mWindowDecoration);
        }
        mWindowDecorationViewModel.onTaskInfoChanged(state.mTaskInfo);

        if (DesktopModeStatus.IS_SUPPORTED) {
            if (taskInfo.isVisible) {
@@ -159,15 +127,6 @@ public class FreeformTaskListener<T extends AutoCloseable>
        }
    }

    private State<T> updateTaskInfo(RunningTaskInfo taskInfo) {
        final State<T> state = mTasks.get(taskInfo.taskId);
        if (state == null) {
            throw new RuntimeException("Task info changed before appearing: #" + taskInfo.taskId);
        }
        state.mTaskInfo = taskInfo;
        return state;
    }

    @Override
    public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
        b.setParent(findTaskSurface(taskId));
@@ -186,103 +145,6 @@ public class FreeformTaskListener<T extends AutoCloseable>
        return mTasks.get(taskId).mLeash;
    }

    /**
     * Creates a window decoration for a transition.
     *
     * @param change the change of this task transition that needs to have the task layer as the
     *               leash
     * @return {@code true} if it creates the window decoration; {@code false} otherwise
     */
    boolean createWindowDecoration(
            TransitionInfo.Change change,
            SurfaceControl.Transaction startT,
            SurfaceControl.Transaction finishT) {
        final State<T> state = createOrUpdateTaskState(change.getTaskInfo(), change.getLeash());
        if (state.mWindowDecoration != null) {
            return false;
        }
        state.mWindowDecoration = mWindowDecorationViewModel.createWindowDecoration(
                state.mTaskInfo, state.mLeash, startT, finishT);
        return true;
    }

    /**
     * Gives out the ownership of the task's window decoration. The given task is leaving (of has
     * left) this task listener. This is the transition system asking for the ownership.
     *
     * @param taskInfo the maximizing task
     * @return the window decor of the maximizing task if any
     */
    T giveWindowDecoration(
            RunningTaskInfo taskInfo,
            SurfaceControl.Transaction startT,
            SurfaceControl.Transaction finishT) {
        T windowDecor;
        final State<T> state = mTasks.get(taskInfo.taskId);
        if (state != null) {
            windowDecor = state.mWindowDecoration;
            state.mWindowDecoration = null;
        } else {
            windowDecor =
                    mWindowDecorOfVanishedTasks.removeReturnOld(taskInfo.taskId);
        }
        if (windowDecor == null) {
            return null;
        }
        mWindowDecorationViewModel.setupWindowDecorationForTransition(
                taskInfo, startT, finishT, windowDecor);
        return windowDecor;
    }

    /**
     * Adopt the incoming window decoration and lets the window decoration prepare for a transition.
     *
     * @param change the change of this task transition that needs to have the task layer as the
     *               leash
     * @param startT the start transaction of this transition
     * @param finishT the finish transaction of this transition
     * @param windowDecor the window decoration to adopt
     * @return {@code true} if it adopts the window decoration; {@code false} otherwise
     */
    boolean adoptWindowDecoration(
            TransitionInfo.Change change,
            SurfaceControl.Transaction startT,
            SurfaceControl.Transaction finishT,
            @Nullable AutoCloseable windowDecor) {
        final State<T> state = createOrUpdateTaskState(change.getTaskInfo(), change.getLeash());
        state.mWindowDecoration = mWindowDecorationViewModel.adoptWindowDecoration(windowDecor);
        if (state.mWindowDecoration != null) {
            mWindowDecorationViewModel.setupWindowDecorationForTransition(
                    state.mTaskInfo, startT, finishT, state.mWindowDecoration);
            return true;
        } else {
            state.mWindowDecoration = mWindowDecorationViewModel.createWindowDecoration(
                    state.mTaskInfo, state.mLeash, startT, finishT);
            return false;
        }
    }

    void onTaskTransitionFinished() {
        if (mWindowDecorOfVanishedTasks.size() == 0) {
            return;
        }
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
                "Clearing window decors of vanished tasks. There could be visual defects "
                + "if any of them is used later in transitions.");
        for (int i = 0; i < mWindowDecorOfVanishedTasks.size(); ++i) {
            releaseWindowDecor(mWindowDecorOfVanishedTasks.valueAt(i));
        }
        mWindowDecorOfVanishedTasks.clear();
    }

    private void releaseWindowDecor(T windowDecor) {
        try {
            windowDecor.close();
        } catch (Exception e) {
            Log.e(TAG, "Failed to release window decoration.", e);
        }
    }

    @Override
    public void dump(PrintWriter pw, String prefix) {
        final String innerPrefix = prefix + "  ";
+2 −2
Original line number Diff line number Diff line
@@ -46,14 +46,14 @@ public class FreeformTaskTransitionHandler
        implements Transitions.TransitionHandler, FreeformTaskTransitionStarter {

    private final Transitions mTransitions;
    private final WindowDecorViewModel<?> mWindowDecorViewModel;
    private final WindowDecorViewModel mWindowDecorViewModel;

    private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();

    public FreeformTaskTransitionHandler(
            ShellInit shellInit,
            Transitions transitions,
            WindowDecorViewModel<?> windowDecorViewModel) {
            WindowDecorViewModel windowDecorViewModel) {
        mTransitions = transitions;
        mWindowDecorViewModel = windowDecorViewModel;
        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+31 −102
Original line number Diff line number Diff line
@@ -16,13 +16,9 @@

package com.android.wm.shell.freeform;

import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;

import android.app.ActivityManager;
import android.content.Context;
import android.os.IBinder;
import android.util.Log;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.TransitionInfo;
@@ -31,9 +27,9 @@ import android.window.WindowContainerToken;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;

import com.android.wm.shell.fullscreen.FullscreenTaskListener;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;

import java.util.ArrayList;
import java.util.Collections;
@@ -47,23 +43,19 @@ import java.util.Map;
 * be a part of transitions.
 */
public class FreeformTaskTransitionObserver implements Transitions.TransitionObserver {
    private static final String TAG = "FreeformTO";

    private final Transitions mTransitions;
    private final FreeformTaskListener<?> mFreeformTaskListener;
    private final FullscreenTaskListener<?> mFullscreenTaskListener;
    private final WindowDecorViewModel mWindowDecorViewModel;

    private final Map<IBinder, List<AutoCloseable>> mTransitionToWindowDecors = new HashMap<>();
    private final Map<IBinder, List<ActivityManager.RunningTaskInfo>> mTransitionToTaskInfo =
            new HashMap<>();

    public FreeformTaskTransitionObserver(
            Context context,
            ShellInit shellInit,
            Transitions transitions,
            FullscreenTaskListener<?> fullscreenTaskListener,
            FreeformTaskListener<?> freeformTaskListener) {
            WindowDecorViewModel windowDecorViewModel) {
        mTransitions = transitions;
        mFreeformTaskListener = freeformTaskListener;
        mFullscreenTaskListener = fullscreenTaskListener;
        mWindowDecorViewModel = windowDecorViewModel;
        if (Transitions.ENABLE_SHELL_TRANSITIONS && FreeformComponents.isFreeformEnabled(context)) {
            shellInit.addInitCallback(this::onInit, this);
        }
@@ -80,7 +72,7 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
            @NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction startT,
            @NonNull SurfaceControl.Transaction finishT) {
        final ArrayList<AutoCloseable> windowDecors = new ArrayList<>();
        final ArrayList<ActivityManager.RunningTaskInfo> taskInfoList = new ArrayList<>();
        final ArrayList<WindowContainerToken> taskParents = new ArrayList<>();
        for (TransitionInfo.Change change : info.getChanges()) {
            if ((change.getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0) {
@@ -110,92 +102,40 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
                    onOpenTransitionReady(change, startT, finishT);
                    break;
                case WindowManager.TRANSIT_CLOSE: {
                    onCloseTransitionReady(change, windowDecors, startT, finishT);
                    taskInfoList.add(change.getTaskInfo());
                    onCloseTransitionReady(change, startT, finishT);
                    break;
                }
                case WindowManager.TRANSIT_CHANGE:
                    onChangeTransitionReady(info.getType(), change, startT, finishT);
                    onChangeTransitionReady(change, startT, finishT);
                    break;
            }
        }
        if (!windowDecors.isEmpty()) {
            mTransitionToWindowDecors.put(transition, windowDecors);
        }
        mTransitionToTaskInfo.put(transition, taskInfoList);
    }

    private void onOpenTransitionReady(
            TransitionInfo.Change change,
            SurfaceControl.Transaction startT,
            SurfaceControl.Transaction finishT) {
        switch (change.getTaskInfo().getWindowingMode()){
            case WINDOWING_MODE_FREEFORM:
                mFreeformTaskListener.createWindowDecoration(change, startT, finishT);
                break;
            case WINDOWING_MODE_FULLSCREEN:
                mFullscreenTaskListener.createWindowDecoration(change, startT, finishT);
                break;
        }
        mWindowDecorViewModel.createWindowDecoration(
                change.getTaskInfo(), change.getLeash(), startT, finishT);
    }

    private void onCloseTransitionReady(
            TransitionInfo.Change change,
            ArrayList<AutoCloseable> windowDecors,
            SurfaceControl.Transaction startT,
            SurfaceControl.Transaction finishT) {
        final AutoCloseable windowDecor;
        switch (change.getTaskInfo().getWindowingMode()) {
            case WINDOWING_MODE_FREEFORM:
                windowDecor = mFreeformTaskListener.giveWindowDecoration(change.getTaskInfo(),
                        startT, finishT);
                break;
            case WINDOWING_MODE_FULLSCREEN:
                windowDecor = mFullscreenTaskListener.giveWindowDecoration(change.getTaskInfo(),
                        startT, finishT);
                break;
            default:
                windowDecor = null;
        }
        if (windowDecor != null) {
            windowDecors.add(windowDecor);
        }
        mWindowDecorViewModel.setupWindowDecorationForTransition(
                change.getTaskInfo(), startT, finishT);
    }

    private void onChangeTransitionReady(
            int type,
            TransitionInfo.Change change,
            SurfaceControl.Transaction startT,
            SurfaceControl.Transaction finishT) {
        AutoCloseable windowDecor = null;

        boolean adopted = false;
        final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
        if (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
            windowDecor = mFreeformTaskListener.giveWindowDecoration(
                    change.getTaskInfo(), startT, finishT);
            if (windowDecor != null) {
                adopted = mFullscreenTaskListener.adoptWindowDecoration(
                        change, startT, finishT, windowDecor);
            } else {
                // will return false if it already has the window decor.
                adopted = mFullscreenTaskListener.createWindowDecoration(change, startT, finishT);
            }
        }

        if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
            windowDecor = mFullscreenTaskListener.giveWindowDecoration(
        mWindowDecorViewModel.setupWindowDecorationForTransition(
                change.getTaskInfo(), startT, finishT);
            if (windowDecor != null) {
                adopted = mFreeformTaskListener.adoptWindowDecoration(
                        change, startT, finishT, windowDecor);
            } else {
                // will return false if it already has the window decor.
                adopted = mFreeformTaskListener.createWindowDecoration(change, startT, finishT);
            }
        }

        if (!adopted) {
            releaseWindowDecor(windowDecor);
        }
    }

    @Override
@@ -203,43 +143,32 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs

    @Override
    public void onTransitionMerged(@NonNull IBinder merged, @NonNull IBinder playing) {
        final List<AutoCloseable> windowDecorsOfMerged = mTransitionToWindowDecors.get(merged);
        if (windowDecorsOfMerged == null) {
        final List<ActivityManager.RunningTaskInfo> infoOfMerged =
                mTransitionToTaskInfo.get(merged);
        if (infoOfMerged == null) {
            // We are adding window decorations of the merged transition to them of the playing
            // transition so if there is none of them there is nothing to do.
            return;
        }
        mTransitionToWindowDecors.remove(merged);
        mTransitionToTaskInfo.remove(merged);

        final List<AutoCloseable> windowDecorsOfPlaying = mTransitionToWindowDecors.get(playing);
        if (windowDecorsOfPlaying != null) {
            windowDecorsOfPlaying.addAll(windowDecorsOfMerged);
        final List<ActivityManager.RunningTaskInfo> infoOfPlaying =
                mTransitionToTaskInfo.get(playing);
        if (infoOfPlaying != null) {
            infoOfPlaying.addAll(infoOfMerged);
        } else {
            mTransitionToWindowDecors.put(playing, windowDecorsOfMerged);
            mTransitionToTaskInfo.put(playing, infoOfMerged);
        }
    }

    @Override
    public void onTransitionFinished(@NonNull IBinder transition, boolean aborted) {
        final List<AutoCloseable> windowDecors = mTransitionToWindowDecors.getOrDefault(
                transition, Collections.emptyList());
        mTransitionToWindowDecors.remove(transition);
        final List<ActivityManager.RunningTaskInfo> taskInfo =
                mTransitionToTaskInfo.getOrDefault(transition, Collections.emptyList());
        mTransitionToTaskInfo.remove(transition);

        for (AutoCloseable windowDecor : windowDecors) {
            releaseWindowDecor(windowDecor);
        }
        mFullscreenTaskListener.onTaskTransitionFinished();
        mFreeformTaskListener.onTaskTransitionFinished();
    }

    private static void releaseWindowDecor(AutoCloseable windowDecor) {
        if (windowDecor == null) {
            return;
        }
        try {
            windowDecor.close();
        } catch (Exception e) {
            Log.e(TAG, "Failed to release window decoration.", e);
        for (int i = 0; i < taskInfo.size(); ++i) {
            mWindowDecorViewModel.destroyWindowDecoration(taskInfo.get(i));
        }
    }
}
Loading