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

Commit fb69800a authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add task focus change support to FocusTransitionListener" into main

parents eddc4e98 f99159c0
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -26,5 +26,11 @@ public interface FocusTransitionListener {
    /**
     * Called when a transition changes the top, focused display.
     */
    void onFocusedDisplayChanged(int displayId);
    default void onFocusedDisplayChanged(int displayId) {}

    /**
     * Called when the per-app or system-wide focus state has changed for a task.
     */
    default void onFocusedTaskChanged(int taskId, boolean isFocusedOnDisplay,
            boolean isFocusedGlobally) {}
}
+8 −6
Original line number Diff line number Diff line
@@ -111,6 +111,7 @@ import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.taskview.TaskViewTransitions;
import com.android.wm.shell.transition.DefaultMixedHandler;
import com.android.wm.shell.transition.FocusTransitionObserver;
import com.android.wm.shell.transition.HomeTransitionObserver;
import com.android.wm.shell.transition.MixedTransitionHandler;
import com.android.wm.shell.transition.Transitions;
@@ -134,14 +135,14 @@ import dagger.Lazy;
import dagger.Module;
import dagger.Provides;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import kotlinx.coroutines.CoroutineScope;
import kotlinx.coroutines.ExperimentalCoroutinesApi;
import kotlinx.coroutines.MainCoroutineDispatcher;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * Provides dependencies from {@link com.android.wm.shell}, these dependencies are only accessible
 * from components within the WM subcomponent (can be explicitly exposed to the SysUIComponent, see
@@ -391,10 +392,11 @@ public abstract class WMShellModule {
            Transitions transitions,
            Optional<DesktopFullImmersiveTransitionHandler> desktopImmersiveTransitionHandler,
            WindowDecorViewModel windowDecorViewModel,
            Optional<TaskChangeListener> taskChangeListener) {
            Optional<TaskChangeListener> taskChangeListener,
            FocusTransitionObserver focusTransitionObserver) {
        return new FreeformTaskTransitionObserver(
                context, shellInit, transitions, desktopImmersiveTransitionHandler,
                windowDecorViewModel, taskChangeListener);
                windowDecorViewModel, taskChangeListener, focusTransitionObserver);
    }

    @WMSingleton
+8 −1
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.window.flags.Flags;
import com.android.wm.shell.desktopmode.DesktopFullImmersiveTransitionHandler;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.FocusTransitionObserver;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;

@@ -50,6 +51,7 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
    private final Optional<DesktopFullImmersiveTransitionHandler> mImmersiveTransitionHandler;
    private final WindowDecorViewModel mWindowDecorViewModel;
    private final Optional<TaskChangeListener> mTaskChangeListener;
    private final FocusTransitionObserver mFocusTransitionObserver;

    private final Map<IBinder, List<ActivityManager.RunningTaskInfo>> mTransitionToTaskInfo =
            new HashMap<>();
@@ -60,11 +62,13 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
            Transitions transitions,
            Optional<DesktopFullImmersiveTransitionHandler> immersiveTransitionHandler,
            WindowDecorViewModel windowDecorViewModel,
            Optional<TaskChangeListener> taskChangeListener) {
            Optional<TaskChangeListener> taskChangeListener,
            FocusTransitionObserver focusTransitionObserver) {
        mTransitions = transitions;
        mImmersiveTransitionHandler = immersiveTransitionHandler;
        mWindowDecorViewModel = windowDecorViewModel;
        mTaskChangeListener = taskChangeListener;
        mFocusTransitionObserver = focusTransitionObserver;
        if (FreeformComponents.isFreeformEnabled(context)) {
            shellInit.addInitCallback(this::onInit, this);
        }
@@ -87,6 +91,9 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
            //  Otherwise window decoration relayout won't run with the immersive state up to date.
            mImmersiveTransitionHandler.ifPresent(h -> h.onTransitionReady(transition));
        }
        // Update focus state first to ensure the correct state can be queried from listeners.
        // TODO(371503964): Remove this once the unified task repository is ready.
        mFocusTransitionObserver.updateFocusState(info);

        final ArrayList<ActivityManager.RunningTaskInfo> taskInfoList = new ArrayList<>();
        final ArrayList<WindowContainerToken> taskParents = new ArrayList<>();
+77 −26
Original line number Diff line number Diff line
@@ -16,7 +16,8 @@

package com.android.wm.shell.transition;

import static android.view.Display.INVALID_DISPLAY;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP;

@@ -24,10 +25,11 @@ import static com.android.window.flags.Flags.enableDisplayFocusInShellTransition
import static com.android.wm.shell.transition.Transitions.TransitionObserver;

import android.annotation.NonNull;
import android.os.IBinder;
import android.app.ActivityManager.RunningTaskInfo;
import android.os.RemoteException;
import android.util.ArraySet;
import android.util.Slog;
import android.view.SurfaceControl;
import android.util.SparseArray;
import android.window.TransitionInfo;

import com.android.wm.shell.shared.FocusTransitionListener;
@@ -43,43 +45,63 @@ import java.util.concurrent.Executor;
 * It reports transitions to callers outside of the process via {@link IFocusTransitionListener},
 * and callers within the process via {@link FocusTransitionListener}.
 */
public class FocusTransitionObserver implements TransitionObserver {
public class FocusTransitionObserver {
    private static final String TAG = FocusTransitionObserver.class.getSimpleName();

    private IFocusTransitionListener mRemoteListener;
    private final Map<FocusTransitionListener, Executor> mLocalListeners =
            new HashMap<>();

    private int mFocusedDisplayId = INVALID_DISPLAY;
    private int mFocusedDisplayId = DEFAULT_DISPLAY;
    private final SparseArray<RunningTaskInfo> mFocusedTaskOnDisplay = new SparseArray<>();

    private final ArraySet<RunningTaskInfo> mTmpTasksToBeNotified = new ArraySet<>();

    public FocusTransitionObserver() {}

    @Override
    public void onTransitionReady(@NonNull IBinder transition,
            @NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction) {
    /**
     * Update display/window focus state from the given transition info and notifies changes if any.
     */
    public void updateFocusState(@NonNull TransitionInfo info) {
        if (!enableDisplayFocusInShellTransitions()) {
            return;
        }
        final List<TransitionInfo.Change> changes = info.getChanges();
        for (int i = changes.size() - 1; i >= 0; i--) {
            final TransitionInfo.Change change = changes.get(i);

            final RunningTaskInfo task = change.getTaskInfo();
            if (task != null
                    && (change.hasFlags(FLAG_MOVED_TO_TOP) || change.getMode() == TRANSIT_OPEN)) {
                final RunningTaskInfo lastFocusedTaskOnDisplay =
                        mFocusedTaskOnDisplay.get(task.displayId);
                if (lastFocusedTaskOnDisplay != null) {
                    mTmpTasksToBeNotified.add(lastFocusedTaskOnDisplay);
                }
                mTmpTasksToBeNotified.add(task);
                mFocusedTaskOnDisplay.put(task.displayId, task);
            }

            if (change.hasFlags(FLAG_IS_DISPLAY) && change.hasFlags(FLAG_MOVED_TO_TOP)) {
                if (mFocusedDisplayId != change.getEndDisplayId()) {
                    final RunningTaskInfo lastGloballyFocusedTask =
                            mFocusedTaskOnDisplay.get(mFocusedDisplayId);
                    if (lastGloballyFocusedTask != null) {
                        mTmpTasksToBeNotified.add(lastGloballyFocusedTask);
                    }
                    mFocusedDisplayId = change.getEndDisplayId();
                    notifyFocusedDisplayChanged();
                    final RunningTaskInfo currentGloballyFocusedTask =
                            mFocusedTaskOnDisplay.get(mFocusedDisplayId);
                    if (currentGloballyFocusedTask != null) {
                        mTmpTasksToBeNotified.add(currentGloballyFocusedTask);
                    }
                return;
                }
            }
        }

    @Override
    public void onTransitionStarting(@NonNull IBinder transition) {}

    @Override
    public void onTransitionMerged(@NonNull IBinder merged, @NonNull IBinder playing) {}

    @Override
    public void onTransitionFinished(@NonNull IBinder transition, boolean aborted) {}
        mTmpTasksToBeNotified.forEach(this::notifyTaskFocusChanged);
        mTmpTasksToBeNotified.clear();
    }

    /**
     * Sets the focus transition listener that receives any transitions resulting in focus switch.
@@ -92,7 +114,10 @@ public class FocusTransitionObserver implements TransitionObserver {
            return;
        }
        mLocalListeners.put(listener, executor);
        executor.execute(() -> listener.onFocusedDisplayChanged(mFocusedDisplayId));
        executor.execute(() -> {
            listener.onFocusedDisplayChanged(mFocusedDisplayId);
            mTmpTasksToBeNotified.forEach(this::notifyTaskFocusChanged);
        });
    }

    /**
@@ -120,13 +145,20 @@ public class FocusTransitionObserver implements TransitionObserver {
        notifyFocusedDisplayChangedToRemote();
    }

    /**
     * Notifies the listener that display focus has changed.
     */
    public void notifyFocusedDisplayChanged() {
    private void notifyTaskFocusChanged(RunningTaskInfo task) {
        final boolean isFocusedOnDisplay = isFocusedOnDisplay(task);
        final boolean isFocusedGlobally = hasGlobalFocus(task);
        mLocalListeners.forEach((listener, executor) ->
                executor.execute(() -> listener.onFocusedTaskChanged(task.taskId,
                        isFocusedOnDisplay, isFocusedGlobally)));
    }

    private void notifyFocusedDisplayChanged() {
        notifyFocusedDisplayChangedToRemote();
        mLocalListeners.forEach((listener, executor) ->
                executor.execute(() -> listener.onFocusedDisplayChanged(mFocusedDisplayId)));
                executor.execute(() -> {
                    listener.onFocusedDisplayChanged(mFocusedDisplayId);
                }));
    }

    private void notifyFocusedDisplayChangedToRemote() {
@@ -138,4 +170,23 @@ public class FocusTransitionObserver implements TransitionObserver {
            }
        }
    }

    private boolean isFocusedOnDisplay(@NonNull RunningTaskInfo task) {
        if (!enableDisplayFocusInShellTransitions()) {
            return task.isFocused;
        }
        final RunningTaskInfo focusedTaskOnDisplay = mFocusedTaskOnDisplay.get(task.displayId);
        return focusedTaskOnDisplay != null && focusedTaskOnDisplay.taskId == task.taskId;
    }

    /**
     * Checks whether the given task has focused globally on the system.
     * (Note {@link RunningTaskInfo#isFocused} represents per-display focus.)
     */
    public boolean hasGlobalFocus(@NonNull RunningTaskInfo task) {
        if (!enableDisplayFocusInShellTransitions()) {
            return task.isFocused;
        }
        return task.displayId == mFocusedDisplayId && isFocusedOnDisplay(task);
    }
}
+0 −2
Original line number Diff line number Diff line
@@ -392,8 +392,6 @@ public class Transitions implements RemoteCallable<Transitions>,

        mShellCommandHandler.addCommandCallback("transitions", this, this);
        mShellCommandHandler.addDumpCallback(this::dump, this);

        registerObserver(mFocusTransitionObserver);
    }

    public boolean isRegistered() {
Loading