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

Commit 824cd1cc authored by Ats Jenk's avatar Ats Jenk Committed by Android (Google) Code Review
Browse files

Merge "Fix hotseat visibility after dragging task to bubble" into main

parents f60cc961 907dd476
Loading
Loading
Loading
Loading
+66 −12
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED;

import static com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_CONVERT_TO_BUBBLE;
import static com.android.wm.shell.transition.Transitions.TransitionObserver;

import android.annotation.NonNull;
@@ -35,6 +36,7 @@ import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SingleInstanceRemoteListener;
import com.android.wm.shell.shared.IHomeTransitionListener;
import com.android.wm.shell.shared.TransitionUtil;
import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;

/**
 * The {@link TransitionObserver} that observes for transitions involving the home
@@ -48,6 +50,8 @@ public class HomeTransitionObserver implements TransitionObserver,

    private @NonNull final Context mContext;
    private @NonNull final ShellExecutor mMainExecutor;
    private Boolean mPendingHomeVisibilityUpdate;

    public HomeTransitionObserver(@NonNull Context context,
            @NonNull ShellExecutor mainExecutor) {
        mContext = context;
@@ -59,16 +63,67 @@ public class HomeTransitionObserver implements TransitionObserver,
            @NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction) {
        if (BubbleAnythingFlagHelper.enableBubbleToFullscreen()) {
            handleTransitionReadyWithBubbleAnything(info);
        } else {
            handleTransitionReady(info);
        }
    }

    private void handleTransitionReady(@NonNull TransitionInfo info) {
        for (TransitionInfo.Change change : info.getChanges()) {
            final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
            if (taskInfo == null
                    || info.getType() == TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP
                    || taskInfo.displayId != DEFAULT_DISPLAY
                    || taskInfo.taskId == -1
                    || !taskInfo.isRunning) {
                continue;
            }
            Boolean homeVisibilityUpdate = getHomeVisibilityUpdate(info, change, taskInfo);
            if (homeVisibilityUpdate != null) {
                notifyHomeVisibilityChanged(homeVisibilityUpdate);
            }
        }
    }

    private void handleTransitionReadyWithBubbleAnything(@NonNull TransitionInfo info) {
        Boolean homeVisibilityUpdate = null;
        for (TransitionInfo.Change change : info.getChanges()) {
            final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
            if (info.getType() == TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP
                    || taskInfo == null
            if (taskInfo == null
                    || taskInfo.displayId != DEFAULT_DISPLAY
                    || taskInfo.taskId == -1
                    || !taskInfo.isRunning) {
                continue;
            }

            Boolean update = getHomeVisibilityUpdate(info, change, taskInfo);
            if (update != null) {
                homeVisibilityUpdate = update;
            }
        }

        if (info.getType() == TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP) {
            // Do not apply at the start of desktop drag as that updates launcher UI visibility.
            // Store the value and apply with a next transition if needed.
            mPendingHomeVisibilityUpdate = homeVisibilityUpdate;
            return;
        }

        if (info.getType() == TRANSIT_CONVERT_TO_BUBBLE && homeVisibilityUpdate == null) {
            // We are converting to bubble and we did not get a change to home visibility in this
            // transition. Apply the value from start of drag.
            homeVisibilityUpdate = mPendingHomeVisibilityUpdate;
        }
        if (homeVisibilityUpdate != null) {
            mPendingHomeVisibilityUpdate = null;
            notifyHomeVisibilityChanged(homeVisibilityUpdate);
        }
    }

    private Boolean getHomeVisibilityUpdate(TransitionInfo info,
            TransitionInfo.Change change, ActivityManager.RunningTaskInfo taskInfo) {
        final int mode = change.getMode();
        final boolean isBackGesture = change.hasFlags(FLAG_BACK_GESTURE_ANIMATED);
        if (taskInfo.getActivityType() == ACTIVITY_TYPE_HOME) {
@@ -76,11 +131,10 @@ public class HomeTransitionObserver implements TransitionObserver,
                    && TransitionUtil.isClosingType(info.getType());
            if (gestureToHomeTransition || TransitionUtil.isClosingMode(mode)
                    || (!isBackGesture && TransitionUtil.isOpeningMode(mode))) {
                    notifyHomeVisibilityChanged(gestureToHomeTransition
                            || TransitionUtil.isOpeningType(mode));
                }
                return gestureToHomeTransition || TransitionUtil.isOpeningType(mode);
            }
        }
        return null;
    }

    @Override
+84 −0
Original line number Diff line number Diff line
@@ -17,36 +17,44 @@
package com.android.wm.shell.transition;

import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_CONVERT_TO_BUBBLE;

import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;

import android.app.ActivityManager;
import android.app.WindowConfiguration.ActivityType;
import android.content.Context;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.platform.test.annotations.EnableFlags;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
import android.window.TransitionInfo.TransitionMode;
import android.window.WindowContainerToken;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;

import com.android.wm.shell.Flags;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
@@ -187,6 +195,72 @@ public class HomeTransitionObserverTest extends ShellTestCase {
        verify(mListener, times(0)).onHomeVisibilityChanged(anyBoolean());
    }

    @Test
    @EnableFlags({Flags.FLAG_ENABLE_BUBBLE_TO_FULLSCREEN, Flags.FLAG_ENABLE_CREATE_ANY_BUBBLE})
    public void testDragTaskToBubbleOverHome_notifiesHomeIsVisible() throws RemoteException {
        ActivityManager.RunningTaskInfo homeTask = createTaskInfo(1, ACTIVITY_TYPE_HOME);
        ActivityManager.RunningTaskInfo bubbleTask = createTaskInfo(2, ACTIVITY_TYPE_STANDARD);

        TransitionInfo startDragTransition =
                new TransitionInfoBuilder(TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP)
                        .addChange(TRANSIT_TO_FRONT, homeTask)
                        .addChange(TRANSIT_TO_BACK, bubbleTask)
                        .build();

        // Start drag to desktop which brings home to front
        mHomeTransitionObserver.onTransitionReady(new Binder(), startDragTransition,
                MockTransactionPool.create(), MockTransactionPool.create());
        // Does not notify home visibility yet
        verify(mListener, never()).onHomeVisibilityChanged(anyBoolean());

        TransitionInfo convertToBubbleTransition =
                new TransitionInfoBuilder(TRANSIT_CONVERT_TO_BUBBLE)
                        .addChange(TRANSIT_TO_FRONT, bubbleTask)
                        .build();

        // Convert to bubble. Transition does not include changes for home task
        mHomeTransitionObserver.onTransitionReady(new Binder(), convertToBubbleTransition,
                MockTransactionPool.create(), MockTransactionPool.create());

        // Notifies home visibility change that was pending from the start of drag
        verify(mListener).onHomeVisibilityChanged(true);
    }

    @Test
    @EnableFlags({Flags.FLAG_ENABLE_BUBBLE_TO_FULLSCREEN, Flags.FLAG_ENABLE_CREATE_ANY_BUBBLE})
    public void testDragTaskToBubbleOverOtherTask_notifiesHomeIsNotVisible()
            throws RemoteException {
        ActivityManager.RunningTaskInfo homeTask = createTaskInfo(1, ACTIVITY_TYPE_HOME);
        ActivityManager.RunningTaskInfo bubbleTask = createTaskInfo(2, ACTIVITY_TYPE_STANDARD);
        ActivityManager.RunningTaskInfo otherTask = createTaskInfo(3, ACTIVITY_TYPE_STANDARD);

        TransitionInfo startDragTransition =
                new TransitionInfoBuilder(TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP)
                        .addChange(TRANSIT_TO_FRONT, homeTask)
                        .addChange(TRANSIT_TO_BACK, bubbleTask)
                        .build();

        // Start drag to desktop which brings home to front
        mHomeTransitionObserver.onTransitionReady(new Binder(), startDragTransition,
                MockTransactionPool.create(), MockTransactionPool.create());
        // Does not notify home visibility yet
        verify(mListener, never()).onHomeVisibilityChanged(anyBoolean());

        TransitionInfo convertToBubbleTransition =
                new TransitionInfoBuilder(TRANSIT_CONVERT_TO_BUBBLE)
                        .addChange(TRANSIT_TO_FRONT, bubbleTask)
                        .addChange(TRANSIT_TO_FRONT, otherTask)
                        .addChange(TRANSIT_TO_BACK, homeTask)
                        .build();

        // Convert to bubble. Transition includes home task to back which updates home visibility
        mHomeTransitionObserver.onTransitionReady(new Binder(), convertToBubbleTransition,
                MockTransactionPool.create(), MockTransactionPool.create());

        // Notifies home visibility change due to home moving to back in the second transition
        verify(mListener).onHomeVisibilityChanged(false);
    }

    @Test
    public void testHomeActivityWithBackGestureNotifiesHomeIsVisibleAfterClose()
            throws RemoteException {
@@ -227,4 +301,14 @@ public class HomeTransitionObserverTest extends ShellTestCase {
        when(change.getMode()).thenReturn(mode);
        taskInfo.isRunning = isRunning;
    }

    private static ActivityManager.RunningTaskInfo createTaskInfo(int taskId, int activityType) {
        ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
        taskInfo.taskId = taskId;
        taskInfo.topActivityType = activityType;
        taskInfo.configuration.windowConfiguration.setActivityType(activityType);
        taskInfo.token = mock(WindowContainerToken.class);
        taskInfo.isRunning = true;
        return taskInfo;
    }
}