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

Commit 3e567854 authored by Pragya Bajoria's avatar Pragya Bajoria
Browse files

Add `TaskChangeListener` interface with `DesktopTaskChangeListener` implementation.

This interface will be used by `FreeformTaskTransitionObserver` to delegate task management.

The implementations of `TaskChangeListener` are responsible for handling all task management.

Change-Id: Ie48990fcd9d1d12ad4d4848f8de09c746bd18bb5
Flag: EXEMPT (no-op in the logic)
Bug: 367268953
parent 7fbcf1d7
Loading
Loading
Loading
Loading
+14 −3
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@ import com.android.wm.shell.desktopmode.DesktopRepository;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.desktopmode.DesktopTasksLimiter;
import com.android.wm.shell.desktopmode.DesktopTasksTransitionObserver;
import com.android.wm.shell.desktopmode.DesktopTaskChangeListener;
import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler;
import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler;
import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler;
@@ -91,6 +92,7 @@ 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.freeform.TaskChangeListener;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarterInitializer;
import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
@@ -386,10 +388,11 @@ public abstract class WMShellModule {
            ShellInit shellInit,
            Transitions transitions,
            Optional<DesktopFullImmersiveTransitionHandler> desktopImmersiveTransitionHandler,
            WindowDecorViewModel windowDecorViewModel) {
            WindowDecorViewModel windowDecorViewModel,
            Optional<TaskChangeListener> taskChangeListener) {
        return new FreeformTaskTransitionObserver(
                context, shellInit, transitions, desktopImmersiveTransitionHandler,
                windowDecorViewModel);
                windowDecorViewModel, taskChangeListener);
    }

    @WMSingleton
@@ -413,7 +416,6 @@ public abstract class WMShellModule {
    // One handed mode
    //


    // Needs the shell main handler for ContentObserver callbacks
    @WMSingleton
    @Provides
@@ -647,6 +649,15 @@ public abstract class WMShellModule {
                recentTasksController.orElse(null), interactionJankMonitor, mainHandler);
    }

    @WMSingleton
    @Provides
    static Optional<TaskChangeListener> provideDesktopTaskChangeListener(Context context) {
        if (DesktopModeStatus.canEnterDesktopMode(context)) {
            return Optional.of(new DesktopTaskChangeListener());
        }
        return Optional.empty();
    }

    @WMSingleton
    @Provides
    static Optional<DesktopTasksLimiter> provideDesktopTasksLimiter(
+44 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.wm.shell.desktopmode

import android.app.ActivityManager.RunningTaskInfo
import com.android.wm.shell.freeform.TaskChangeListener

/** Manages tasks handling specific to Android Desktop Mode. */
class DesktopTaskChangeListener: TaskChangeListener {

  override fun onTaskOpening(taskInfo: RunningTaskInfo) {
    // TODO: b/367268953 - Connect this with DesktopRepository.
  }

  override fun onTaskChanging(taskInfo: RunningTaskInfo) {
    // TODO: b/367268953 - Connect this with DesktopRepository.
  }

  override fun onTaskMovingToFront(taskInfo: RunningTaskInfo) {
    // TODO: b/367268953 - Connect this with DesktopRepository.
  }

  override fun onTaskMovingToBack(taskInfo: RunningTaskInfo) {
    // TODO: b/367268953 - Connect this with DesktopRepository.
  }

  override fun onTaskClosing(taskInfo: RunningTaskInfo) {
    // TODO: b/367268953 - Connect this with DesktopRepository.
  }
}
+16 −3
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
    private final Transitions mTransitions;
    private final Optional<DesktopFullImmersiveTransitionHandler> mImmersiveTransitionHandler;
    private final WindowDecorViewModel mWindowDecorViewModel;
    private final Optional<TaskChangeListener> mTaskChangeListener;

    private final Map<IBinder, List<ActivityManager.RunningTaskInfo>> mTransitionToTaskInfo =
            new HashMap<>();
@@ -58,10 +59,12 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
            ShellInit shellInit,
            Transitions transitions,
            Optional<DesktopFullImmersiveTransitionHandler> immersiveTransitionHandler,
            WindowDecorViewModel windowDecorViewModel) {
            WindowDecorViewModel windowDecorViewModel,
            Optional<TaskChangeListener> taskChangeListener) {
        mTransitions = transitions;
        mImmersiveTransitionHandler = immersiveTransitionHandler;
        mWindowDecorViewModel = windowDecorViewModel;
        mTaskChangeListener = taskChangeListener;
        if (Transitions.ENABLE_SHELL_TRANSITIONS && FreeformComponents.isFreeformEnabled(context)) {
            shellInit.addInitCallback(this::onInit, this);
        }
@@ -133,6 +136,8 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
            TransitionInfo.Change change,
            SurfaceControl.Transaction startT,
            SurfaceControl.Transaction finishT) {
        mTaskChangeListener.ifPresent(
            listener -> listener.onTaskOpening(change.getTaskInfo()));
        mWindowDecorViewModel.onTaskOpening(
            change.getTaskInfo(), change.getLeash(), startT, finishT);
    }
@@ -141,21 +146,29 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
            TransitionInfo.Change change,
            SurfaceControl.Transaction startT,
            SurfaceControl.Transaction finishT) {
        mTaskChangeListener.ifPresent(
            listener -> listener.onTaskClosing(change.getTaskInfo()));
        mWindowDecorViewModel.onTaskClosing(change.getTaskInfo(), startT, finishT);

    }

    private void onChangeTransitionReady(
            TransitionInfo.Change change,
            SurfaceControl.Transaction startT,
            SurfaceControl.Transaction finishT) {
        mTaskChangeListener.ifPresent(listener ->
            listener.onTaskChanging(change.getTaskInfo()));
        mWindowDecorViewModel.onTaskChanging(
                change.getTaskInfo(), change.getLeash(), startT, finishT);
    }


    private void onToFrontTransitionReady(
            TransitionInfo.Change change,
            SurfaceControl.Transaction startT,
            SurfaceControl.Transaction finishT) {
        mTaskChangeListener.ifPresent(
                listener -> listener.onTaskMovingToFront(change.getTaskInfo()));
        mWindowDecorViewModel.onTaskChanging(
                change.getTaskInfo(), change.getLeash(), startT, finishT);
    }
+41 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.wm.shell.freeform

import android.app.ActivityManager.RunningTaskInfo;

/**
 * Interface used by [FreeformTaskTransitionObserver] to manage freeform tasks.
 *
 * The implementations are responsible for handle all the task management.
 */
interface TaskChangeListener {
    /** Notifies a task opening in freeform mode. */
    fun onTaskOpening(taskInfo: RunningTaskInfo)

    /** Notifies a task info update on the given task. */
    fun onTaskChanging(taskInfo: RunningTaskInfo)

    /** Notifies a task moving to the front. */
    fun onTaskMovingToFront(taskInfo: RunningTaskInfo)

    /** Notifies a task moving to the back. */
    fun onTaskMovingToBack(taskInfo: RunningTaskInfo)

    /** Notifies a task is closing. */
    fun onTaskClosing(taskInfo: RunningTaskInfo)
}
 No newline at end of file
+82 −13
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.TRANSIT_CHANGE;

import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -41,12 +43,16 @@ import android.window.WindowContainerToken;
import androidx.test.filters.SmallTest;

import com.android.window.flags.Flags;

import com.android.wm.shell.desktopmode.DesktopTaskChangeListener;
import com.android.wm.shell.desktopmode.DesktopFullImmersiveTransitionHandler;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.TransitionInfoBuilder;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;

import java.util.Optional;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -57,14 +63,12 @@ import org.mockito.MockitoAnnotations;
import java.util.Optional;

/**
 * Tests of {@link FreeformTaskTransitionObserver}
 * Tests for {@link FreeformTaskTransitionObserver}.
 */
@SmallTest
public class FreeformTaskTransitionObserverTest {

    @Rule
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    @Mock
    private ShellInit mShellInit;
    @Mock
@@ -73,7 +77,8 @@ public class FreeformTaskTransitionObserverTest {
    private DesktopFullImmersiveTransitionHandler mDesktopFullImmersiveTransitionHandler;
    @Mock
    private WindowDecorViewModel mWindowDecorViewModel;

    @Mock
    private TaskChangeListener mTaskChangeListener;
    private FreeformTaskTransitionObserver mTransitionObserver;

    @Before
@@ -89,7 +94,7 @@ public class FreeformTaskTransitionObserverTest {
        mTransitionObserver = new FreeformTaskTransitionObserver(
                context, mShellInit, mTransitions,
                Optional.of(mDesktopFullImmersiveTransitionHandler),
                mWindowDecorViewModel);
                mWindowDecorViewModel, Optional.of(mTaskChangeListener));
        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
            final ArgumentCaptor<Runnable> initRunnableCaptor = ArgumentCaptor.forClass(
                    Runnable.class);
@@ -102,12 +107,12 @@ public class FreeformTaskTransitionObserverTest {
    }

    @Test
    public void testRegistersObserverAtInit() {
    public void init_registersObserver() {
        verify(mTransitions).registerObserver(same(mTransitionObserver));
    }

    @Test
    public void testCreatesWindowDecorOnOpenTransition_freeform() {
    public void openTransition_createsWindowDecor() {
        final TransitionInfo.Change change =
                createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FREEFORM);
        final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0)
@@ -124,7 +129,55 @@ public class FreeformTaskTransitionObserverTest {
    }

    @Test
    public void testPreparesWindowDecorOnCloseTransition_freeform() {
    public void openTransition_notifiesOnTaskOpening() {
        final TransitionInfo.Change change =
                createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FREEFORM);
        final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0)
                .addChange(change).build();

        final IBinder transition = mock(IBinder.class);
        final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
        final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
        mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
        mTransitionObserver.onTransitionStarting(transition);

        verify(mTaskChangeListener).onTaskOpening(change.getTaskInfo());
    }

    @Test
    public void toFrontTransition_notifiesOnTaskMovingToFront() {
        final TransitionInfo.Change change =
                createChange(TRANSIT_TO_FRONT, /* taskId= */ 1, WINDOWING_MODE_FREEFORM);
        final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_TO_FRONT, /* flags= */ 0)
                .addChange(change).build();

        final IBinder transition = mock(IBinder.class);
        final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
        final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
        mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
        mTransitionObserver.onTransitionStarting(transition);

        verify(mTaskChangeListener).onTaskMovingToFront(change.getTaskInfo());
    }

    @Test
    public void changeTransition_notifiesOnTaskChanging() {
        final TransitionInfo.Change change =
                createChange(TRANSIT_CHANGE, /* taskId= */ 1, WINDOWING_MODE_FREEFORM);
        final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CHANGE, /* flags= */ 0)
                .addChange(change).build();

        final IBinder transition = mock(IBinder.class);
        final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
        final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
        mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
        mTransitionObserver.onTransitionStarting(transition);

        verify(mTaskChangeListener).onTaskChanging(change.getTaskInfo());
    }

    @Test
    public void closeTransition_preparesWindowDecor() {
        final TransitionInfo.Change change =
                createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM);
        final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CLOSE, 0)
@@ -141,7 +194,23 @@ public class FreeformTaskTransitionObserverTest {
    }

    @Test
    public void testDoesntCloseWindowDecorDuringCloseTransition() throws Exception {
    public void closeTransition_notifiesOnTaskClosing() {
        final TransitionInfo.Change change =
                createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM);
        final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CLOSE, 0)
                .addChange(change).build();

        final IBinder transition = mock(IBinder.class);
        final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
        final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
        mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
        mTransitionObserver.onTransitionStarting(transition);

        verify(mTaskChangeListener).onTaskClosing(change.getTaskInfo());
    }

    @Test
    public void closeTransition_doesntCloseWindowDecorDuringTransition() throws Exception {
        final TransitionInfo.Change change =
                createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM);
        final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CLOSE, 0)
@@ -157,7 +226,7 @@ public class FreeformTaskTransitionObserverTest {
    }

    @Test
    public void testClosesWindowDecorAfterCloseTransition() throws Exception {
    public void closeTransition_closesWindowDecorAfterTransition() throws Exception {
        final TransitionInfo.Change change =
                createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM);
        final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CLOSE, 0)
@@ -176,7 +245,7 @@ public class FreeformTaskTransitionObserverTest {
    }

    @Test
    public void testClosesMergedWindowDecorationAfterTransitionFinishes() throws Exception {
    public void transitionFinished_closesMergedWindowDecoration() throws Exception {
        // The playing transition
        final TransitionInfo.Change change1 =
                createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FREEFORM);
@@ -207,7 +276,7 @@ public class FreeformTaskTransitionObserverTest {
    }

    @Test
    public void testClosesAllWindowDecorsOnTransitionMergeAfterCloseTransitions() throws Exception {
    public void closeTransition_closesWindowDecorsOnTransitionMerge() throws Exception {
        // The playing transition
        final TransitionInfo.Change change1 =
                createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM);