Loading libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/FocusTransitionListener.java +7 −1 Original line number Diff line number Diff line Loading @@ -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) {} } libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +8 −6 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading Loading @@ -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 Loading libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java +8 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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<>(); Loading @@ -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); } Loading @@ -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<>(); Loading libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java +77 −26 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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. Loading @@ -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); }); } /** Loading Loading @@ -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() { Loading @@ -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); } } libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +0 −2 Original line number Diff line number Diff line Loading @@ -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 Loading
libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/FocusTransitionListener.java +7 −1 Original line number Diff line number Diff line Loading @@ -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) {} }
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +8 −6 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading Loading @@ -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 Loading
libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java +8 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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<>(); Loading @@ -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); } Loading @@ -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<>(); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java +77 −26 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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. Loading @@ -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); }); } /** Loading Loading @@ -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() { Loading @@ -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); } }
libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +0 −2 Original line number Diff line number Diff line Loading @@ -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