Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +6 −6 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -316,7 +316,7 @@ public abstract class WMShellBaseModule { // @BindsOptionalOf abstract WindowDecorViewModel<?> optionalWindowDecorViewModel(); abstract WindowDecorViewModel optionalWindowDecorViewModel(); // // Unfold transition Loading Loading @@ -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, Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +8 −10 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -183,7 +182,7 @@ public abstract class WMShellModule { @WMSingleton @Provides static WindowDecorViewModel<?> provideWindowDecorViewModel( static WindowDecorViewModel provideWindowDecorViewModel( Context context, @ShellMainThread Handler mainHandler, @ShellMainThread Choreographer mainChoreographer, Loading @@ -209,7 +208,7 @@ public abstract class WMShellModule { @Provides @DynamicOverride static FreeformComponents provideFreeformComponents( FreeformTaskListener<?> taskListener, FreeformTaskListener taskListener, FreeformTaskTransitionHandler transitionHandler, FreeformTaskTransitionObserver transitionObserver) { return new FreeformComponents( Loading @@ -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); } Loading @@ -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); } Loading @@ -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); } // Loading libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java +18 −156 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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(); } Loading @@ -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); Loading @@ -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) { Loading @@ -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)); Loading @@ -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 + " "; Loading libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java +2 −2 Original line number Diff line number Diff line Loading @@ -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) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java +31 −102 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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); } Loading @@ -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) { Loading Loading @@ -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 Loading @@ -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
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +6 −6 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -316,7 +316,7 @@ public abstract class WMShellBaseModule { // @BindsOptionalOf abstract WindowDecorViewModel<?> optionalWindowDecorViewModel(); abstract WindowDecorViewModel optionalWindowDecorViewModel(); // // Unfold transition Loading Loading @@ -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, Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +8 −10 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -183,7 +182,7 @@ public abstract class WMShellModule { @WMSingleton @Provides static WindowDecorViewModel<?> provideWindowDecorViewModel( static WindowDecorViewModel provideWindowDecorViewModel( Context context, @ShellMainThread Handler mainHandler, @ShellMainThread Choreographer mainChoreographer, Loading @@ -209,7 +208,7 @@ public abstract class WMShellModule { @Provides @DynamicOverride static FreeformComponents provideFreeformComponents( FreeformTaskListener<?> taskListener, FreeformTaskListener taskListener, FreeformTaskTransitionHandler transitionHandler, FreeformTaskTransitionObserver transitionObserver) { return new FreeformComponents( Loading @@ -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); } Loading @@ -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); } Loading @@ -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); } // Loading
libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java +18 −156 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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(); } Loading @@ -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); Loading @@ -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) { Loading @@ -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)); Loading @@ -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 + " "; Loading
libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java +2 −2 Original line number Diff line number Diff line Loading @@ -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) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java +31 −102 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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); } Loading @@ -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) { Loading Loading @@ -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 Loading @@ -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)); } } }