Loading core/java/android/view/IWindowSession.aidl +10 −0 Original line number Diff line number Diff line Loading @@ -370,4 +370,14 @@ interface IWindowSession { boolean transferEmbeddedTouchFocusToHost(IWindow embeddedWindow); boolean transferHostTouchGestureToEmbedded(IWindow hostWindow, IBinder transferTouchToken); /** * Moves the focus to the adjacent window if there is one in the given direction. This can only * move the focus to the window in the same leaf task. * * @param fromWindow The calling window that the focus is moved from. * @param direction The {@link android.view.View.FocusDirection} that the new focus should go. * @return {@code true} if the focus changes. Otherwise, {@code false}. */ boolean moveFocusToAdjacentWindow(IWindow fromWindow, int direction); } core/java/android/view/ViewRootImpl.java +18 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.view; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.content.pm.ActivityInfo.OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS; import static android.graphics.HardwareRenderer.SYNC_CONTEXT_IS_STOPPED; import static android.graphics.HardwareRenderer.SYNC_LOST_SURFACE_REWARD_IF_FOUND; Loading Loading @@ -7236,7 +7237,7 @@ public final class ViewRootImpl implements ViewParent, } private boolean performFocusNavigation(KeyEvent event) { int direction = 0; @FocusDirection int direction = 0; switch (event.getKeyCode()) { case KeyEvent.KEYCODE_DPAD_LEFT: if (event.hasNoModifiers()) { Loading Loading @@ -7288,6 +7289,8 @@ public final class ViewRootImpl implements ViewParent, isFastScrolling)); return true; } } else if (moveFocusToAdjacentWindow(direction)) { return true; } // Give the focused view a last chance to handle the dpad key. Loading @@ -7297,11 +7300,25 @@ public final class ViewRootImpl implements ViewParent, } else { if (mView.restoreDefaultFocus()) { return true; } else if (moveFocusToAdjacentWindow(direction)) { return true; } } } return false; } private boolean moveFocusToAdjacentWindow(@FocusDirection int direction) { if (getConfiguration().windowConfiguration.getWindowingMode() != WINDOWING_MODE_MULTI_WINDOW) { return false; } try { return mWindowSession.moveFocusToAdjacentWindow(mWindow, direction); } catch (RemoteException e) { return false; } } private boolean performKeyboardGroupNavigation(int direction) { final View focused = mView.findFocus(); Loading core/java/android/view/WindowlessWindowManager.java +8 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.os.RemoteCallback; import android.os.RemoteException; import android.util.Log; import android.util.MergedConfiguration; import android.view.View.FocusDirection; import android.view.WindowInsets.Type.InsetsType; import android.window.ClientWindowFrames; import android.window.OnBackInvokedCallbackInfo; Loading Loading @@ -665,6 +666,13 @@ public class WindowlessWindowManager implements IWindowSession { return false; } @Override public boolean moveFocusToAdjacentWindow(IWindow fromWindow, @FocusDirection int direction) { Log.e(TAG, "Received request to moveFocusToAdjacentWindow on" + " WindowlessWindowManager. We shouldn't get here!"); return false; } void setParentInterface(@Nullable ISurfaceControlViewHostParent parentInterface) { IBinder oldInterface = mParentInterface == null ? null : mParentInterface.asBinder(); IBinder newInterface = parentInterface == null ? null : parentInterface.asBinder(); Loading services/core/java/com/android/server/wm/Session.java +12 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ import android.view.InsetsState; import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.View; import android.view.View.FocusDirection; import android.view.WindowInsets; import android.view.WindowInsets.Type.InsetsType; import android.view.WindowManager; Loading Loading @@ -1000,6 +1001,17 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { } return didTransfer; } @Override public boolean moveFocusToAdjacentWindow(IWindow fromWindow, @FocusDirection int direction) { final long identity = Binder.clearCallingIdentity(); try { return mService.moveFocusToAdjacentWindow(this, fromWindow, direction); } finally { Binder.restoreCallingIdentity(identity); } } @Override public void generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm, RemoteCallback callback) { Loading services/core/java/com/android/server/wm/WindowManagerService.java +61 −0 Original line number Diff line number Diff line Loading @@ -287,6 +287,7 @@ import android.view.SurfaceControlViewHost; import android.view.SurfaceSession; import android.view.TaskTransitionSpec; import android.view.View; import android.view.View.FocusDirection; import android.view.ViewDebug; import android.view.WindowContentFrameStats; import android.view.WindowInsets; Loading Loading @@ -9104,6 +9105,66 @@ public class WindowManagerService extends IWindowManager.Stub win.mClient); } boolean moveFocusToAdjacentWindow(Session session, IWindow fromWindow, @FocusDirection int direction) { synchronized (mGlobalLock) { final WindowState fromWin = windowForClientLocked(session, fromWindow, false); if (fromWin == null || !fromWin.isFocused()) { return false; } final TaskFragment fromFragment = fromWin.getTaskFragment(); if (fromFragment == null) { return false; } final TaskFragment adjacentFragment = fromFragment.getAdjacentTaskFragment(); if (adjacentFragment == null || adjacentFragment.asTask() != null) { // Don't move the focus to another task. return false; } final Rect fromBounds = fromFragment.getBounds(); final Rect adjacentBounds = adjacentFragment.getBounds(); switch (direction) { case View.FOCUS_LEFT: if (adjacentBounds.left >= fromBounds.left) { return false; } break; case View.FOCUS_UP: if (adjacentBounds.top >= fromBounds.top) { return false; } break; case View.FOCUS_RIGHT: if (adjacentBounds.right <= fromBounds.right) { return false; } break; case View.FOCUS_DOWN: if (adjacentBounds.bottom <= fromBounds.bottom) { return false; } break; case View.FOCUS_BACKWARD: case View.FOCUS_FORWARD: // These are not absolute directions. Skip checking the bounds. break; default: return false; } final ActivityRecord topRunningActivity = adjacentFragment.topRunningActivity( true /* focusableOnly */); if (topRunningActivity == null) { return false; } moveDisplayToTopInternal(topRunningActivity.getDisplayId()); handleTaskFocusChange(topRunningActivity.getTask(), topRunningActivity); if (fromWin.isFocused()) { return false; } } return true; } /** Return whether layer tracing is enabled */ public boolean isLayerTracing() { if (!checkCallingPermission( Loading Loading
core/java/android/view/IWindowSession.aidl +10 −0 Original line number Diff line number Diff line Loading @@ -370,4 +370,14 @@ interface IWindowSession { boolean transferEmbeddedTouchFocusToHost(IWindow embeddedWindow); boolean transferHostTouchGestureToEmbedded(IWindow hostWindow, IBinder transferTouchToken); /** * Moves the focus to the adjacent window if there is one in the given direction. This can only * move the focus to the window in the same leaf task. * * @param fromWindow The calling window that the focus is moved from. * @param direction The {@link android.view.View.FocusDirection} that the new focus should go. * @return {@code true} if the focus changes. Otherwise, {@code false}. */ boolean moveFocusToAdjacentWindow(IWindow fromWindow, int direction); }
core/java/android/view/ViewRootImpl.java +18 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.view; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.content.pm.ActivityInfo.OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS; import static android.graphics.HardwareRenderer.SYNC_CONTEXT_IS_STOPPED; import static android.graphics.HardwareRenderer.SYNC_LOST_SURFACE_REWARD_IF_FOUND; Loading Loading @@ -7236,7 +7237,7 @@ public final class ViewRootImpl implements ViewParent, } private boolean performFocusNavigation(KeyEvent event) { int direction = 0; @FocusDirection int direction = 0; switch (event.getKeyCode()) { case KeyEvent.KEYCODE_DPAD_LEFT: if (event.hasNoModifiers()) { Loading Loading @@ -7288,6 +7289,8 @@ public final class ViewRootImpl implements ViewParent, isFastScrolling)); return true; } } else if (moveFocusToAdjacentWindow(direction)) { return true; } // Give the focused view a last chance to handle the dpad key. Loading @@ -7297,11 +7300,25 @@ public final class ViewRootImpl implements ViewParent, } else { if (mView.restoreDefaultFocus()) { return true; } else if (moveFocusToAdjacentWindow(direction)) { return true; } } } return false; } private boolean moveFocusToAdjacentWindow(@FocusDirection int direction) { if (getConfiguration().windowConfiguration.getWindowingMode() != WINDOWING_MODE_MULTI_WINDOW) { return false; } try { return mWindowSession.moveFocusToAdjacentWindow(mWindow, direction); } catch (RemoteException e) { return false; } } private boolean performKeyboardGroupNavigation(int direction) { final View focused = mView.findFocus(); Loading
core/java/android/view/WindowlessWindowManager.java +8 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.os.RemoteCallback; import android.os.RemoteException; import android.util.Log; import android.util.MergedConfiguration; import android.view.View.FocusDirection; import android.view.WindowInsets.Type.InsetsType; import android.window.ClientWindowFrames; import android.window.OnBackInvokedCallbackInfo; Loading Loading @@ -665,6 +666,13 @@ public class WindowlessWindowManager implements IWindowSession { return false; } @Override public boolean moveFocusToAdjacentWindow(IWindow fromWindow, @FocusDirection int direction) { Log.e(TAG, "Received request to moveFocusToAdjacentWindow on" + " WindowlessWindowManager. We shouldn't get here!"); return false; } void setParentInterface(@Nullable ISurfaceControlViewHostParent parentInterface) { IBinder oldInterface = mParentInterface == null ? null : mParentInterface.asBinder(); IBinder newInterface = parentInterface == null ? null : parentInterface.asBinder(); Loading
services/core/java/com/android/server/wm/Session.java +12 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ import android.view.InsetsState; import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.View; import android.view.View.FocusDirection; import android.view.WindowInsets; import android.view.WindowInsets.Type.InsetsType; import android.view.WindowManager; Loading Loading @@ -1000,6 +1001,17 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { } return didTransfer; } @Override public boolean moveFocusToAdjacentWindow(IWindow fromWindow, @FocusDirection int direction) { final long identity = Binder.clearCallingIdentity(); try { return mService.moveFocusToAdjacentWindow(this, fromWindow, direction); } finally { Binder.restoreCallingIdentity(identity); } } @Override public void generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm, RemoteCallback callback) { Loading
services/core/java/com/android/server/wm/WindowManagerService.java +61 −0 Original line number Diff line number Diff line Loading @@ -287,6 +287,7 @@ import android.view.SurfaceControlViewHost; import android.view.SurfaceSession; import android.view.TaskTransitionSpec; import android.view.View; import android.view.View.FocusDirection; import android.view.ViewDebug; import android.view.WindowContentFrameStats; import android.view.WindowInsets; Loading Loading @@ -9104,6 +9105,66 @@ public class WindowManagerService extends IWindowManager.Stub win.mClient); } boolean moveFocusToAdjacentWindow(Session session, IWindow fromWindow, @FocusDirection int direction) { synchronized (mGlobalLock) { final WindowState fromWin = windowForClientLocked(session, fromWindow, false); if (fromWin == null || !fromWin.isFocused()) { return false; } final TaskFragment fromFragment = fromWin.getTaskFragment(); if (fromFragment == null) { return false; } final TaskFragment adjacentFragment = fromFragment.getAdjacentTaskFragment(); if (adjacentFragment == null || adjacentFragment.asTask() != null) { // Don't move the focus to another task. return false; } final Rect fromBounds = fromFragment.getBounds(); final Rect adjacentBounds = adjacentFragment.getBounds(); switch (direction) { case View.FOCUS_LEFT: if (adjacentBounds.left >= fromBounds.left) { return false; } break; case View.FOCUS_UP: if (adjacentBounds.top >= fromBounds.top) { return false; } break; case View.FOCUS_RIGHT: if (adjacentBounds.right <= fromBounds.right) { return false; } break; case View.FOCUS_DOWN: if (adjacentBounds.bottom <= fromBounds.bottom) { return false; } break; case View.FOCUS_BACKWARD: case View.FOCUS_FORWARD: // These are not absolute directions. Skip checking the bounds. break; default: return false; } final ActivityRecord topRunningActivity = adjacentFragment.topRunningActivity( true /* focusableOnly */); if (topRunningActivity == null) { return false; } moveDisplayToTopInternal(topRunningActivity.getDisplayId()); handleTaskFocusChange(topRunningActivity.getTask(), topRunningActivity); if (fromWin.isFocused()) { return false; } } return true; } /** Return whether layer tracing is enabled */ public boolean isLayerTracing() { if (!checkCallingPermission( Loading