Merge "Extract remote insets controller out of DisplayImeController" into sc-v2-dev
This commit is contained in:
@@ -20,7 +20,9 @@ import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCR
|
|||||||
|
|
||||||
import com.android.wm.shell.apppairs.AppPairsController;
|
import com.android.wm.shell.apppairs.AppPairsController;
|
||||||
import com.android.wm.shell.bubbles.BubbleController;
|
import com.android.wm.shell.bubbles.BubbleController;
|
||||||
|
import com.android.wm.shell.common.DisplayController;
|
||||||
import com.android.wm.shell.common.DisplayImeController;
|
import com.android.wm.shell.common.DisplayImeController;
|
||||||
|
import com.android.wm.shell.common.DisplayInsetsController;
|
||||||
import com.android.wm.shell.common.ShellExecutor;
|
import com.android.wm.shell.common.ShellExecutor;
|
||||||
import com.android.wm.shell.common.annotations.ExternalThread;
|
import com.android.wm.shell.common.annotations.ExternalThread;
|
||||||
import com.android.wm.shell.draganddrop.DragAndDropController;
|
import com.android.wm.shell.draganddrop.DragAndDropController;
|
||||||
@@ -39,7 +41,9 @@ import java.util.Optional;
|
|||||||
public class ShellInitImpl {
|
public class ShellInitImpl {
|
||||||
private static final String TAG = ShellInitImpl.class.getSimpleName();
|
private static final String TAG = ShellInitImpl.class.getSimpleName();
|
||||||
|
|
||||||
|
private final DisplayController mDisplayController;
|
||||||
private final DisplayImeController mDisplayImeController;
|
private final DisplayImeController mDisplayImeController;
|
||||||
|
private final DisplayInsetsController mDisplayInsetsController;
|
||||||
private final DragAndDropController mDragAndDropController;
|
private final DragAndDropController mDragAndDropController;
|
||||||
private final ShellTaskOrganizer mShellTaskOrganizer;
|
private final ShellTaskOrganizer mShellTaskOrganizer;
|
||||||
private final Optional<BubbleController> mBubblesOptional;
|
private final Optional<BubbleController> mBubblesOptional;
|
||||||
@@ -55,7 +59,10 @@ public class ShellInitImpl {
|
|||||||
|
|
||||||
private final InitImpl mImpl = new InitImpl();
|
private final InitImpl mImpl = new InitImpl();
|
||||||
|
|
||||||
public ShellInitImpl(DisplayImeController displayImeController,
|
public ShellInitImpl(
|
||||||
|
DisplayController displayController,
|
||||||
|
DisplayImeController displayImeController,
|
||||||
|
DisplayInsetsController displayInsetsController,
|
||||||
DragAndDropController dragAndDropController,
|
DragAndDropController dragAndDropController,
|
||||||
ShellTaskOrganizer shellTaskOrganizer,
|
ShellTaskOrganizer shellTaskOrganizer,
|
||||||
Optional<BubbleController> bubblesOptional,
|
Optional<BubbleController> bubblesOptional,
|
||||||
@@ -68,7 +75,9 @@ public class ShellInitImpl {
|
|||||||
Transitions transitions,
|
Transitions transitions,
|
||||||
StartingWindowController startingWindow,
|
StartingWindowController startingWindow,
|
||||||
ShellExecutor mainExecutor) {
|
ShellExecutor mainExecutor) {
|
||||||
|
mDisplayController = displayController;
|
||||||
mDisplayImeController = displayImeController;
|
mDisplayImeController = displayImeController;
|
||||||
|
mDisplayInsetsController = displayInsetsController;
|
||||||
mDragAndDropController = dragAndDropController;
|
mDragAndDropController = dragAndDropController;
|
||||||
mShellTaskOrganizer = shellTaskOrganizer;
|
mShellTaskOrganizer = shellTaskOrganizer;
|
||||||
mBubblesOptional = bubblesOptional;
|
mBubblesOptional = bubblesOptional;
|
||||||
@@ -88,7 +97,9 @@ public class ShellInitImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
// Start listening for display changes
|
// Start listening for display and insets changes
|
||||||
|
mDisplayController.initialize();
|
||||||
|
mDisplayInsetsController.initialize();
|
||||||
mDisplayImeController.startMonitorDisplays();
|
mDisplayImeController.startMonitorDisplays();
|
||||||
|
|
||||||
// Setup the shell organizer
|
// Setup the shell organizer
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.android.wm.shell.common;
|
package com.android.wm.shell.common;
|
||||||
|
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
import android.util.Slog;
|
||||||
import android.view.IDisplayWindowRotationCallback;
|
import android.view.IDisplayWindowRotationCallback;
|
||||||
import android.view.IDisplayWindowRotationController;
|
import android.view.IDisplayWindowRotationController;
|
||||||
import android.view.IWindowManager;
|
import android.view.IWindowManager;
|
||||||
@@ -27,6 +28,7 @@ import androidx.annotation.BinderThread;
|
|||||||
import com.android.wm.shell.common.annotations.ShellMainThread;
|
import com.android.wm.shell.common.annotations.ShellMainThread;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This module deals with display rotations coming from WM. When WM starts a rotation: after it has
|
* This module deals with display rotations coming from WM. When WM starts a rotation: after it has
|
||||||
@@ -35,14 +37,14 @@ import java.util.ArrayList;
|
|||||||
* rotation.
|
* rotation.
|
||||||
*/
|
*/
|
||||||
public class DisplayChangeController {
|
public class DisplayChangeController {
|
||||||
|
private static final String TAG = DisplayChangeController.class.getSimpleName();
|
||||||
|
|
||||||
private final ShellExecutor mMainExecutor;
|
private final ShellExecutor mMainExecutor;
|
||||||
private final IWindowManager mWmService;
|
private final IWindowManager mWmService;
|
||||||
private final IDisplayWindowRotationController mControllerImpl;
|
private final IDisplayWindowRotationController mControllerImpl;
|
||||||
|
|
||||||
private final ArrayList<OnDisplayChangingListener> mRotationListener =
|
private final CopyOnWriteArrayList<OnDisplayChangingListener> mRotationListener =
|
||||||
new ArrayList<>();
|
new CopyOnWriteArrayList<>();
|
||||||
private final ArrayList<OnDisplayChangingListener> mTmpListeners = new ArrayList<>();
|
|
||||||
|
|
||||||
public DisplayChangeController(IWindowManager wmService, ShellExecutor mainExecutor) {
|
public DisplayChangeController(IWindowManager wmService, ShellExecutor mainExecutor) {
|
||||||
mMainExecutor = mainExecutor;
|
mMainExecutor = mainExecutor;
|
||||||
@@ -59,34 +61,26 @@ public class DisplayChangeController {
|
|||||||
* Adds a display rotation controller.
|
* Adds a display rotation controller.
|
||||||
*/
|
*/
|
||||||
public void addRotationListener(OnDisplayChangingListener listener) {
|
public void addRotationListener(OnDisplayChangingListener listener) {
|
||||||
synchronized (mRotationListener) {
|
mRotationListener.add(listener);
|
||||||
mRotationListener.add(listener);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a display rotation controller.
|
* Removes a display rotation controller.
|
||||||
*/
|
*/
|
||||||
public void removeRotationListener(OnDisplayChangingListener listener) {
|
public void removeRotationListener(OnDisplayChangingListener listener) {
|
||||||
synchronized (mRotationListener) {
|
mRotationListener.remove(listener);
|
||||||
mRotationListener.remove(listener);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onRotateDisplay(int displayId, final int fromRotation, final int toRotation,
|
private void onRotateDisplay(int displayId, final int fromRotation, final int toRotation,
|
||||||
IDisplayWindowRotationCallback callback) {
|
IDisplayWindowRotationCallback callback) {
|
||||||
WindowContainerTransaction t = new WindowContainerTransaction();
|
WindowContainerTransaction t = new WindowContainerTransaction();
|
||||||
synchronized (mRotationListener) {
|
for (OnDisplayChangingListener c : mRotationListener) {
|
||||||
mTmpListeners.clear();
|
|
||||||
// Make a local copy in case the handlers add/remove themselves.
|
|
||||||
mTmpListeners.addAll(mRotationListener);
|
|
||||||
}
|
|
||||||
for (OnDisplayChangingListener c : mTmpListeners) {
|
|
||||||
c.onRotateDisplay(displayId, fromRotation, toRotation, t);
|
c.onRotateDisplay(displayId, fromRotation, toRotation, t);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
callback.continueRotateDisplay(toRotation, t);
|
callback.continueRotateDisplay(toRotation, t);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
|
Slog.e(TAG, "Failed to continue rotation", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import android.util.SparseArray;
|
|||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
import android.view.IDisplayWindowListener;
|
import android.view.IDisplayWindowListener;
|
||||||
import android.view.IWindowManager;
|
import android.view.IWindowManager;
|
||||||
|
import android.view.InsetsState;
|
||||||
|
|
||||||
import androidx.annotation.BinderThread;
|
import androidx.annotation.BinderThread;
|
||||||
|
|
||||||
@@ -52,14 +53,6 @@ public class DisplayController {
|
|||||||
private final SparseArray<DisplayRecord> mDisplays = new SparseArray<>();
|
private final SparseArray<DisplayRecord> mDisplays = new SparseArray<>();
|
||||||
private final ArrayList<OnDisplaysChangedListener> mDisplayChangedListeners = new ArrayList<>();
|
private final ArrayList<OnDisplaysChangedListener> mDisplayChangedListeners = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a display by id from DisplayManager.
|
|
||||||
*/
|
|
||||||
public Display getDisplay(int displayId) {
|
|
||||||
final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
|
|
||||||
return displayManager.getDisplay(displayId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DisplayController(Context context, IWindowManager wmService,
|
public DisplayController(Context context, IWindowManager wmService,
|
||||||
ShellExecutor mainExecutor) {
|
ShellExecutor mainExecutor) {
|
||||||
mMainExecutor = mainExecutor;
|
mMainExecutor = mainExecutor;
|
||||||
@@ -67,13 +60,27 @@ public class DisplayController {
|
|||||||
mWmService = wmService;
|
mWmService = wmService;
|
||||||
mChangeController = new DisplayChangeController(mWmService, mainExecutor);
|
mChangeController = new DisplayChangeController(mWmService, mainExecutor);
|
||||||
mDisplayContainerListener = new DisplayWindowListenerImpl();
|
mDisplayContainerListener = new DisplayWindowListenerImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the window listener.
|
||||||
|
*/
|
||||||
|
public void initialize() {
|
||||||
try {
|
try {
|
||||||
mWmService.registerDisplayWindowListener(mDisplayContainerListener);
|
mWmService.registerDisplayWindowListener(mDisplayContainerListener);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
throw new RuntimeException("Unable to register hierarchy listener");
|
throw new RuntimeException("Unable to register display controller");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a display by id from DisplayManager.
|
||||||
|
*/
|
||||||
|
public Display getDisplay(int displayId) {
|
||||||
|
final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
|
||||||
|
return displayManager.getDisplay(displayId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the DisplayLayout associated with a display.
|
* Gets the DisplayLayout associated with a display.
|
||||||
*/
|
*/
|
||||||
@@ -90,6 +97,16 @@ public class DisplayController {
|
|||||||
return r != null ? r.mContext : null;
|
return r != null ? r.mContext : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the insets for a given display.
|
||||||
|
*/
|
||||||
|
public void updateDisplayInsets(int displayId, InsetsState state) {
|
||||||
|
final DisplayRecord r = mDisplays.get(displayId);
|
||||||
|
if (r != null) {
|
||||||
|
r.setInsets(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a display window-container listener. It will get notified whenever a display's
|
* Add a display window-container listener. It will get notified whenever a display's
|
||||||
* configuration changes or when displays are added/removed from the WM hierarchy.
|
* configuration changes or when displays are added/removed from the WM hierarchy.
|
||||||
@@ -134,17 +151,18 @@ public class DisplayController {
|
|||||||
if (mDisplays.get(displayId) != null) {
|
if (mDisplays.get(displayId) != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Display display = getDisplay(displayId);
|
final Display display = getDisplay(displayId);
|
||||||
if (display == null) {
|
if (display == null) {
|
||||||
// It's likely that the display is private to some app and thus not
|
// It's likely that the display is private to some app and thus not
|
||||||
// accessible by system-ui.
|
// accessible by system-ui.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DisplayRecord record = new DisplayRecord();
|
|
||||||
record.mDisplayId = displayId;
|
final Context context = (displayId == Display.DEFAULT_DISPLAY)
|
||||||
record.mContext = (displayId == Display.DEFAULT_DISPLAY) ? mContext
|
? mContext
|
||||||
: mContext.createDisplayContext(display);
|
: mContext.createDisplayContext(display);
|
||||||
record.mDisplayLayout = new DisplayLayout(record.mContext, display);
|
final DisplayRecord record = new DisplayRecord(displayId);
|
||||||
|
record.setDisplayLayout(context, new DisplayLayout(context, display));
|
||||||
mDisplays.put(displayId, record);
|
mDisplays.put(displayId, record);
|
||||||
for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
|
for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
|
||||||
mDisplayChangedListeners.get(i).onDisplayAdded(displayId);
|
mDisplayChangedListeners.get(i).onDisplayAdded(displayId);
|
||||||
@@ -154,24 +172,23 @@ public class DisplayController {
|
|||||||
|
|
||||||
private void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
|
private void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
|
||||||
synchronized (mDisplays) {
|
synchronized (mDisplays) {
|
||||||
DisplayRecord dr = mDisplays.get(displayId);
|
final DisplayRecord dr = mDisplays.get(displayId);
|
||||||
if (dr == null) {
|
if (dr == null) {
|
||||||
Slog.w(TAG, "Skipping Display Configuration change on non-added"
|
Slog.w(TAG, "Skipping Display Configuration change on non-added"
|
||||||
+ " display.");
|
+ " display.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Display display = getDisplay(displayId);
|
final Display display = getDisplay(displayId);
|
||||||
if (display == null) {
|
if (display == null) {
|
||||||
Slog.w(TAG, "Skipping Display Configuration change on invalid"
|
Slog.w(TAG, "Skipping Display Configuration change on invalid"
|
||||||
+ " display. It may have been removed.");
|
+ " display. It may have been removed.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Context perDisplayContext = mContext;
|
final Context perDisplayContext = (displayId == Display.DEFAULT_DISPLAY)
|
||||||
if (displayId != Display.DEFAULT_DISPLAY) {
|
? mContext
|
||||||
perDisplayContext = mContext.createDisplayContext(display);
|
: mContext.createDisplayContext(display);
|
||||||
}
|
final Context context = perDisplayContext.createConfigurationContext(newConfig);
|
||||||
dr.mContext = perDisplayContext.createConfigurationContext(newConfig);
|
dr.setDisplayLayout(context, new DisplayLayout(context, display));
|
||||||
dr.mDisplayLayout = new DisplayLayout(dr.mContext, display);
|
|
||||||
for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
|
for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
|
||||||
mDisplayChangedListeners.get(i).onDisplayConfigurationChanged(
|
mDisplayChangedListeners.get(i).onDisplayConfigurationChanged(
|
||||||
displayId, newConfig);
|
displayId, newConfig);
|
||||||
@@ -219,9 +236,25 @@ public class DisplayController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class DisplayRecord {
|
private static class DisplayRecord {
|
||||||
int mDisplayId;
|
private int mDisplayId;
|
||||||
Context mContext;
|
private Context mContext;
|
||||||
DisplayLayout mDisplayLayout;
|
private DisplayLayout mDisplayLayout;
|
||||||
|
private InsetsState mInsetsState = new InsetsState();
|
||||||
|
|
||||||
|
private DisplayRecord(int displayId) {
|
||||||
|
mDisplayId = displayId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDisplayLayout(Context context, DisplayLayout displayLayout) {
|
||||||
|
mContext = context;
|
||||||
|
mDisplayLayout = displayLayout;
|
||||||
|
mDisplayLayout.setInsets(mContext.getResources(), mInsetsState);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setInsets(InsetsState state) {
|
||||||
|
mInsetsState = state;
|
||||||
|
mDisplayLayout.setInsets(mContext.getResources(), state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@BinderThread
|
@BinderThread
|
||||||
|
|||||||
@@ -69,14 +69,17 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
|
|||||||
protected final Executor mMainExecutor;
|
protected final Executor mMainExecutor;
|
||||||
private final TransactionPool mTransactionPool;
|
private final TransactionPool mTransactionPool;
|
||||||
private final DisplayController mDisplayController;
|
private final DisplayController mDisplayController;
|
||||||
|
private final DisplayInsetsController mDisplayInsetsController;
|
||||||
private final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>();
|
private final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>();
|
||||||
private final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>();
|
private final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
public DisplayImeController(IWindowManager wmService, DisplayController displayController,
|
public DisplayImeController(IWindowManager wmService, DisplayController displayController,
|
||||||
|
DisplayInsetsController displayInsetsController,
|
||||||
Executor mainExecutor, TransactionPool transactionPool) {
|
Executor mainExecutor, TransactionPool transactionPool) {
|
||||||
mWmService = wmService;
|
mWmService = wmService;
|
||||||
mDisplayController = displayController;
|
mDisplayController = displayController;
|
||||||
|
mDisplayInsetsController = displayInsetsController;
|
||||||
mMainExecutor = mainExecutor;
|
mMainExecutor = mainExecutor;
|
||||||
mTransactionPool = transactionPool;
|
mTransactionPool = transactionPool;
|
||||||
}
|
}
|
||||||
@@ -110,11 +113,11 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisplayRemoved(int displayId) {
|
public void onDisplayRemoved(int displayId) {
|
||||||
try {
|
PerDisplay pd = mImePerDisplay.get(displayId);
|
||||||
mWmService.setDisplayWindowInsetsController(displayId, null);
|
if (pd == null) {
|
||||||
} catch (RemoteException e) {
|
return;
|
||||||
Slog.w(TAG, "Unable to remove insets controller on display " + displayId);
|
|
||||||
}
|
}
|
||||||
|
pd.unregister();
|
||||||
mImePerDisplay.remove(displayId);
|
mImePerDisplay.remove(displayId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,12 +199,10 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** An implementation of {@link IDisplayWindowInsetsController} for a given display id. */
|
/** An implementation of {@link IDisplayWindowInsetsController} for a given display id. */
|
||||||
public class PerDisplay {
|
public class PerDisplay implements DisplayInsetsController.OnInsetsChangedListener {
|
||||||
final int mDisplayId;
|
final int mDisplayId;
|
||||||
final InsetsState mInsetsState = new InsetsState();
|
final InsetsState mInsetsState = new InsetsState();
|
||||||
final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
|
final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
|
||||||
protected final DisplayWindowInsetsControllerImpl mInsetsControllerImpl =
|
|
||||||
new DisplayWindowInsetsControllerImpl();
|
|
||||||
InsetsSourceControl mImeSourceControl = null;
|
InsetsSourceControl mImeSourceControl = null;
|
||||||
int mAnimationDirection = DIRECTION_NONE;
|
int mAnimationDirection = DIRECTION_NONE;
|
||||||
ValueAnimator mAnimation = null;
|
ValueAnimator mAnimation = null;
|
||||||
@@ -216,14 +217,15 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void register() {
|
public void register() {
|
||||||
try {
|
mDisplayInsetsController.addInsetsChangedListener(mDisplayId, this);
|
||||||
mWmService.setDisplayWindowInsetsController(mDisplayId, mInsetsControllerImpl);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Slog.w(TAG, "Unable to set insets controller on display " + mDisplayId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void insetsChanged(InsetsState insetsState) {
|
public void unregister() {
|
||||||
|
mDisplayInsetsController.removeInsetsChangedListener(mDisplayId, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insetsChanged(InsetsState insetsState) {
|
||||||
if (mInsetsState.equals(insetsState)) {
|
if (mInsetsState.equals(insetsState)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -241,8 +243,9 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
protected void insetsControlChanged(InsetsState insetsState,
|
public void insetsControlChanged(InsetsState insetsState,
|
||||||
InsetsSourceControl[] activeControls) {
|
InsetsSourceControl[] activeControls) {
|
||||||
insetsChanged(insetsState);
|
insetsChanged(insetsState);
|
||||||
InsetsSourceControl imeSourceControl = null;
|
InsetsSourceControl imeSourceControl = null;
|
||||||
@@ -303,7 +306,8 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void showInsets(int types, boolean fromIme) {
|
@Override
|
||||||
|
public void showInsets(int types, boolean fromIme) {
|
||||||
if ((types & WindowInsets.Type.ime()) == 0) {
|
if ((types & WindowInsets.Type.ime()) == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -311,8 +315,8 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
|
|||||||
startAnimation(true /* show */, false /* forceRestart */);
|
startAnimation(true /* show */, false /* forceRestart */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected void hideInsets(int types, boolean fromIme) {
|
public void hideInsets(int types, boolean fromIme) {
|
||||||
if ((types & WindowInsets.Type.ime()) == 0) {
|
if ((types & WindowInsets.Type.ime()) == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -320,6 +324,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
|
|||||||
startAnimation(false /* show */, false /* forceRestart */);
|
startAnimation(false /* show */, false /* forceRestart */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void topFocusedWindowChanged(String packageName) {
|
public void topFocusedWindowChanged(String packageName) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
@@ -493,47 +498,6 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
|
|||||||
dispatchVisibilityChanged(mDisplayId, isShowing);
|
dispatchVisibilityChanged(mDisplayId, isShowing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
@BinderThread
|
|
||||||
public class DisplayWindowInsetsControllerImpl
|
|
||||||
extends IDisplayWindowInsetsController.Stub {
|
|
||||||
@Override
|
|
||||||
public void topFocusedWindowChanged(String packageName) throws RemoteException {
|
|
||||||
mMainExecutor.execute(() -> {
|
|
||||||
PerDisplay.this.topFocusedWindowChanged(packageName);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void insetsChanged(InsetsState insetsState) throws RemoteException {
|
|
||||||
mMainExecutor.execute(() -> {
|
|
||||||
PerDisplay.this.insetsChanged(insetsState);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void insetsControlChanged(InsetsState insetsState,
|
|
||||||
InsetsSourceControl[] activeControls) throws RemoteException {
|
|
||||||
mMainExecutor.execute(() -> {
|
|
||||||
PerDisplay.this.insetsControlChanged(insetsState, activeControls);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showInsets(int types, boolean fromIme) throws RemoteException {
|
|
||||||
mMainExecutor.execute(() -> {
|
|
||||||
PerDisplay.this.showInsets(types, fromIme);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void hideInsets(int types, boolean fromIme) throws RemoteException {
|
|
||||||
mMainExecutor.execute(() -> {
|
|
||||||
PerDisplay.this.hideInsets(types, fromIme);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeImeSurface() {
|
void removeImeSurface() {
|
||||||
|
|||||||
@@ -0,0 +1,265 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.common;
|
||||||
|
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.util.Slog;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
import android.view.IDisplayWindowInsetsController;
|
||||||
|
import android.view.IWindowManager;
|
||||||
|
import android.view.InsetsSourceControl;
|
||||||
|
import android.view.InsetsState;
|
||||||
|
|
||||||
|
import androidx.annotation.BinderThread;
|
||||||
|
|
||||||
|
import com.android.wm.shell.common.annotations.ShellMainThread;
|
||||||
|
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages insets from the core.
|
||||||
|
*/
|
||||||
|
public class DisplayInsetsController implements DisplayController.OnDisplaysChangedListener {
|
||||||
|
private static final String TAG = "DisplayInsetsController";
|
||||||
|
|
||||||
|
private final IWindowManager mWmService;
|
||||||
|
private final ShellExecutor mMainExecutor;
|
||||||
|
private final DisplayController mDisplayController;
|
||||||
|
private final SparseArray<PerDisplay> mInsetsPerDisplay = new SparseArray<>();
|
||||||
|
private final SparseArray<CopyOnWriteArrayList<OnInsetsChangedListener>> mListeners =
|
||||||
|
new SparseArray<>();
|
||||||
|
|
||||||
|
public DisplayInsetsController(IWindowManager wmService, DisplayController displayController,
|
||||||
|
ShellExecutor mainExecutor) {
|
||||||
|
mWmService = wmService;
|
||||||
|
mDisplayController = displayController;
|
||||||
|
mMainExecutor = mainExecutor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts listening for insets for each display.
|
||||||
|
**/
|
||||||
|
public void initialize() {
|
||||||
|
mDisplayController.addDisplayWindowListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a callback to listen for insets changes for a particular display. Note that the
|
||||||
|
* listener will not be updated with the existing state of the insets on that display.
|
||||||
|
*/
|
||||||
|
public void addInsetsChangedListener(int displayId, OnInsetsChangedListener listener) {
|
||||||
|
CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(displayId);
|
||||||
|
if (listeners == null) {
|
||||||
|
listeners = new CopyOnWriteArrayList<>();
|
||||||
|
mListeners.put(displayId, listeners);
|
||||||
|
}
|
||||||
|
if (!listeners.contains(listener)) {
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a callback listening for insets changes from a particular display.
|
||||||
|
*/
|
||||||
|
public void removeInsetsChangedListener(int displayId, OnInsetsChangedListener listener) {
|
||||||
|
CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(displayId);
|
||||||
|
if (listeners == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
listeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisplayAdded(int displayId) {
|
||||||
|
PerDisplay pd = new PerDisplay(displayId);
|
||||||
|
pd.register();
|
||||||
|
mInsetsPerDisplay.put(displayId, pd);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisplayRemoved(int displayId) {
|
||||||
|
PerDisplay pd = mInsetsPerDisplay.get(displayId);
|
||||||
|
if (pd == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pd.unregister();
|
||||||
|
mInsetsPerDisplay.remove(displayId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of {@link IDisplayWindowInsetsController} for a given display id.
|
||||||
|
**/
|
||||||
|
public class PerDisplay {
|
||||||
|
private final int mDisplayId;
|
||||||
|
private final DisplayWindowInsetsControllerImpl mInsetsControllerImpl =
|
||||||
|
new DisplayWindowInsetsControllerImpl();
|
||||||
|
|
||||||
|
public PerDisplay(int displayId) {
|
||||||
|
mDisplayId = displayId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void register() {
|
||||||
|
try {
|
||||||
|
mWmService.setDisplayWindowInsetsController(mDisplayId, mInsetsControllerImpl);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Slog.w(TAG, "Unable to set insets controller on display " + mDisplayId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unregister() {
|
||||||
|
try {
|
||||||
|
mWmService.setDisplayWindowInsetsController(mDisplayId, null);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Slog.w(TAG, "Unable to remove insets controller on display " + mDisplayId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insetsChanged(InsetsState insetsState) {
|
||||||
|
CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
|
||||||
|
if (listeners == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mDisplayController.updateDisplayInsets(mDisplayId, insetsState);
|
||||||
|
for (OnInsetsChangedListener listener : listeners) {
|
||||||
|
listener.insetsChanged(insetsState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insetsControlChanged(InsetsState insetsState,
|
||||||
|
InsetsSourceControl[] activeControls) {
|
||||||
|
CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
|
||||||
|
if (listeners == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (OnInsetsChangedListener listener : listeners) {
|
||||||
|
listener.insetsControlChanged(insetsState, activeControls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showInsets(int types, boolean fromIme) {
|
||||||
|
CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
|
||||||
|
if (listeners == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (OnInsetsChangedListener listener : listeners) {
|
||||||
|
listener.showInsets(types, fromIme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hideInsets(int types, boolean fromIme) {
|
||||||
|
CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
|
||||||
|
if (listeners == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (OnInsetsChangedListener listener : listeners) {
|
||||||
|
listener.hideInsets(types, fromIme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void topFocusedWindowChanged(String packageName) {
|
||||||
|
CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
|
||||||
|
if (listeners == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (OnInsetsChangedListener listener : listeners) {
|
||||||
|
listener.topFocusedWindowChanged(packageName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@BinderThread
|
||||||
|
private class DisplayWindowInsetsControllerImpl
|
||||||
|
extends IDisplayWindowInsetsController.Stub {
|
||||||
|
@Override
|
||||||
|
public void topFocusedWindowChanged(String packageName) throws RemoteException {
|
||||||
|
mMainExecutor.execute(() -> {
|
||||||
|
PerDisplay.this.topFocusedWindowChanged(packageName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insetsChanged(InsetsState insetsState) throws RemoteException {
|
||||||
|
mMainExecutor.execute(() -> {
|
||||||
|
PerDisplay.this.insetsChanged(insetsState);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insetsControlChanged(InsetsState insetsState,
|
||||||
|
InsetsSourceControl[] activeControls) throws RemoteException {
|
||||||
|
mMainExecutor.execute(() -> {
|
||||||
|
PerDisplay.this.insetsControlChanged(insetsState, activeControls);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showInsets(int types, boolean fromIme) throws RemoteException {
|
||||||
|
mMainExecutor.execute(() -> {
|
||||||
|
PerDisplay.this.showInsets(types, fromIme);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void hideInsets(int types, boolean fromIme) throws RemoteException {
|
||||||
|
mMainExecutor.execute(() -> {
|
||||||
|
PerDisplay.this.hideInsets(types, fromIme);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets notified whenever the insets change.
|
||||||
|
*
|
||||||
|
* @see IDisplayWindowInsetsController
|
||||||
|
*/
|
||||||
|
@ShellMainThread
|
||||||
|
public interface OnInsetsChangedListener {
|
||||||
|
/**
|
||||||
|
* Called when top focused window changes to determine whether or not to take over insets
|
||||||
|
* control. Won't be called if config_remoteInsetsControllerControlsSystemBars is false.
|
||||||
|
* @param packageName: Passes the top package name
|
||||||
|
*/
|
||||||
|
void topFocusedWindowChanged(String packageName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the window insets configuration has changed.
|
||||||
|
*/
|
||||||
|
void insetsChanged(InsetsState insetsState);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when this window retrieved control over a specified set of insets sources.
|
||||||
|
*/
|
||||||
|
void insetsControlChanged(InsetsState insetsState,
|
||||||
|
InsetsSourceControl[] activeControls);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a set of insets source window should be shown by policy.
|
||||||
|
*
|
||||||
|
* @param types internal insets types (WindowInsets.Type.InsetsType) to show
|
||||||
|
* @param fromIme true if this request originated from IME (InputMethodService).
|
||||||
|
*/
|
||||||
|
void showInsets(int types, boolean fromIme);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a set of insets source window should be hidden by policy.
|
||||||
|
*
|
||||||
|
* @param types internal insets types (WindowInsets.Type.InsetsType) to hide
|
||||||
|
* @param fromIme true if this request originated from IME (InputMethodService).
|
||||||
|
*/
|
||||||
|
void hideInsets(int types, boolean fromIme);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON
|
|||||||
import static android.util.RotationUtils.rotateBounds;
|
import static android.util.RotationUtils.rotateBounds;
|
||||||
import static android.util.RotationUtils.rotateInsets;
|
import static android.util.RotationUtils.rotateInsets;
|
||||||
import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
|
import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
|
||||||
|
import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
|
||||||
import static android.view.Surface.ROTATION_0;
|
import static android.view.Surface.ROTATION_0;
|
||||||
import static android.view.Surface.ROTATION_270;
|
import static android.view.Surface.ROTATION_270;
|
||||||
import static android.view.Surface.ROTATION_90;
|
import static android.view.Surface.ROTATION_90;
|
||||||
@@ -44,7 +45,10 @@ import android.view.Display;
|
|||||||
import android.view.DisplayCutout;
|
import android.view.DisplayCutout;
|
||||||
import android.view.DisplayInfo;
|
import android.view.DisplayInfo;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
|
import android.view.InsetsSource;
|
||||||
|
import android.view.InsetsState;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
import android.view.WindowInsets;
|
||||||
|
|
||||||
import com.android.internal.R;
|
import com.android.internal.R;
|
||||||
|
|
||||||
@@ -85,6 +89,7 @@ public class DisplayLayout {
|
|||||||
private boolean mAllowSeamlessRotationDespiteNavBarMoving = false;
|
private boolean mAllowSeamlessRotationDespiteNavBarMoving = false;
|
||||||
private boolean mNavigationBarCanMove = false;
|
private boolean mNavigationBarCanMove = false;
|
||||||
private boolean mReverseDefaultRotation = false;
|
private boolean mReverseDefaultRotation = false;
|
||||||
|
private InsetsState mInsetsState = new InsetsState();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
@@ -105,7 +110,8 @@ public class DisplayLayout {
|
|||||||
== other.mAllowSeamlessRotationDespiteNavBarMoving
|
== other.mAllowSeamlessRotationDespiteNavBarMoving
|
||||||
&& mNavigationBarCanMove == other.mNavigationBarCanMove
|
&& mNavigationBarCanMove == other.mNavigationBarCanMove
|
||||||
&& mReverseDefaultRotation == other.mReverseDefaultRotation
|
&& mReverseDefaultRotation == other.mReverseDefaultRotation
|
||||||
&& mNavBarFrameHeight == other.mNavBarFrameHeight;
|
&& mNavBarFrameHeight == other.mNavBarFrameHeight
|
||||||
|
&& Objects.equals(mInsetsState, other.mInsetsState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -113,7 +119,7 @@ public class DisplayLayout {
|
|||||||
return Objects.hash(mUiMode, mWidth, mHeight, mCutout, mRotation, mDensityDpi,
|
return Objects.hash(mUiMode, mWidth, mHeight, mCutout, mRotation, mDensityDpi,
|
||||||
mNonDecorInsets, mStableInsets, mHasNavigationBar, mHasStatusBar,
|
mNonDecorInsets, mStableInsets, mHasNavigationBar, mHasStatusBar,
|
||||||
mNavBarFrameHeight, mAllowSeamlessRotationDespiteNavBarMoving,
|
mNavBarFrameHeight, mAllowSeamlessRotationDespiteNavBarMoving,
|
||||||
mNavigationBarCanMove, mReverseDefaultRotation);
|
mNavigationBarCanMove, mReverseDefaultRotation, mInsetsState);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -164,6 +170,7 @@ public class DisplayLayout {
|
|||||||
mNavBarFrameHeight = dl.mNavBarFrameHeight;
|
mNavBarFrameHeight = dl.mNavBarFrameHeight;
|
||||||
mNonDecorInsets.set(dl.mNonDecorInsets);
|
mNonDecorInsets.set(dl.mNonDecorInsets);
|
||||||
mStableInsets.set(dl.mStableInsets);
|
mStableInsets.set(dl.mStableInsets);
|
||||||
|
mInsetsState.set(dl.mInsetsState, true /* copySources */);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init(DisplayInfo info, Resources res, boolean hasNavigationBar,
|
private void init(DisplayInfo info, Resources res, boolean hasNavigationBar,
|
||||||
@@ -183,9 +190,17 @@ public class DisplayLayout {
|
|||||||
recalcInsets(res);
|
recalcInsets(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the current insets.
|
||||||
|
*/
|
||||||
|
public void setInsets(Resources res, InsetsState state) {
|
||||||
|
mInsetsState = state;
|
||||||
|
recalcInsets(res);
|
||||||
|
}
|
||||||
|
|
||||||
private void recalcInsets(Resources res) {
|
private void recalcInsets(Resources res) {
|
||||||
computeNonDecorInsets(res, mRotation, mWidth, mHeight, mCutout, mUiMode, mNonDecorInsets,
|
computeNonDecorInsets(res, mRotation, mWidth, mHeight, mCutout, mInsetsState, mUiMode,
|
||||||
mHasNavigationBar);
|
mNonDecorInsets, mHasNavigationBar);
|
||||||
mStableInsets.set(mNonDecorInsets);
|
mStableInsets.set(mNonDecorInsets);
|
||||||
if (mHasStatusBar) {
|
if (mHasStatusBar) {
|
||||||
convertNonDecorInsetsToStableInsets(res, mStableInsets, mWidth, mHeight, mHasStatusBar);
|
convertNonDecorInsetsToStableInsets(res, mStableInsets, mWidth, mHeight, mHasStatusBar);
|
||||||
@@ -259,7 +274,7 @@ public class DisplayLayout {
|
|||||||
return mWidth > mHeight;
|
return mWidth > mHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the navbar frame height (used by ime). */
|
/** Get the navbar frame (or window) height (used by ime). */
|
||||||
public int navBarFrameHeight() {
|
public int navBarFrameHeight() {
|
||||||
return mNavBarFrameHeight;
|
return mNavBarFrameHeight;
|
||||||
}
|
}
|
||||||
@@ -328,21 +343,29 @@ public class DisplayLayout {
|
|||||||
* @param outInsets the insets to return
|
* @param outInsets the insets to return
|
||||||
*/
|
*/
|
||||||
static void computeNonDecorInsets(Resources res, int displayRotation, int displayWidth,
|
static void computeNonDecorInsets(Resources res, int displayRotation, int displayWidth,
|
||||||
int displayHeight, DisplayCutout displayCutout, int uiMode, Rect outInsets,
|
int displayHeight, DisplayCutout displayCutout, InsetsState insetsState, int uiMode,
|
||||||
boolean hasNavigationBar) {
|
Rect outInsets, boolean hasNavigationBar) {
|
||||||
outInsets.setEmpty();
|
outInsets.setEmpty();
|
||||||
|
|
||||||
// Only navigation bar
|
// Only navigation bar
|
||||||
if (hasNavigationBar) {
|
if (hasNavigationBar) {
|
||||||
|
final InsetsSource extraNavBar = insetsState.getSource(ITYPE_EXTRA_NAVIGATION_BAR);
|
||||||
|
final boolean hasExtraNav = extraNavBar != null && extraNavBar.isVisible();
|
||||||
int position = navigationBarPosition(res, displayWidth, displayHeight, displayRotation);
|
int position = navigationBarPosition(res, displayWidth, displayHeight, displayRotation);
|
||||||
int navBarSize =
|
int navBarSize =
|
||||||
getNavigationBarSize(res, position, displayWidth > displayHeight, uiMode);
|
getNavigationBarSize(res, position, displayWidth > displayHeight, uiMode);
|
||||||
if (position == NAV_BAR_BOTTOM) {
|
if (position == NAV_BAR_BOTTOM) {
|
||||||
outInsets.bottom = navBarSize;
|
outInsets.bottom = hasExtraNav
|
||||||
|
? Math.max(navBarSize, extraNavBar.getFrame().height())
|
||||||
|
: navBarSize;
|
||||||
} else if (position == NAV_BAR_RIGHT) {
|
} else if (position == NAV_BAR_RIGHT) {
|
||||||
outInsets.right = navBarSize;
|
outInsets.right = hasExtraNav
|
||||||
|
? Math.max(navBarSize, extraNavBar.getFrame().width())
|
||||||
|
: navBarSize;
|
||||||
} else if (position == NAV_BAR_LEFT) {
|
} else if (position == NAV_BAR_LEFT) {
|
||||||
outInsets.left = navBarSize;
|
outInsets.left = hasExtraNav
|
||||||
|
? Math.max(navBarSize, extraNavBar.getFrame().width())
|
||||||
|
: navBarSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,13 +387,13 @@ public class DisplayLayout {
|
|||||||
* @param outInsets the insets to return
|
* @param outInsets the insets to return
|
||||||
*/
|
*/
|
||||||
static void computeStableInsets(Resources res, int displayRotation, int displayWidth,
|
static void computeStableInsets(Resources res, int displayRotation, int displayWidth,
|
||||||
int displayHeight, DisplayCutout displayCutout, int uiMode, Rect outInsets,
|
int displayHeight, DisplayCutout displayCutout, InsetsState insetsState, int uiMode,
|
||||||
boolean hasNavigationBar, boolean hasStatusBar) {
|
Rect outInsets, boolean hasNavigationBar, boolean hasStatusBar) {
|
||||||
outInsets.setEmpty();
|
outInsets.setEmpty();
|
||||||
|
|
||||||
// Navigation bar and status bar.
|
// Navigation bar and status bar.
|
||||||
computeNonDecorInsets(res, displayRotation, displayWidth, displayHeight, displayCutout,
|
computeNonDecorInsets(res, displayRotation, displayWidth, displayHeight, displayCutout,
|
||||||
uiMode, outInsets, hasNavigationBar);
|
insetsState, uiMode, outInsets, hasNavigationBar);
|
||||||
convertNonDecorInsetsToStableInsets(res, outInsets, displayWidth, displayHeight,
|
convertNonDecorInsetsToStableInsets(res, outInsets, displayWidth, displayHeight,
|
||||||
hasStatusBar);
|
hasStatusBar);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public class DisplayImeControllerTest {
|
|||||||
mT = mock(SurfaceControl.Transaction.class);
|
mT = mock(SurfaceControl.Transaction.class);
|
||||||
mMock = mock(IInputMethodManager.class);
|
mMock = mock(IInputMethodManager.class);
|
||||||
mExecutor = spy(Runnable::run);
|
mExecutor = spy(Runnable::run);
|
||||||
mPerDisplay = new DisplayImeController(null, null, mExecutor, new TransactionPool() {
|
mPerDisplay = new DisplayImeController(null, null, null, mExecutor, new TransactionPool() {
|
||||||
@Override
|
@Override
|
||||||
public SurfaceControl.Transaction acquire() {
|
public SurfaceControl.Transaction acquire() {
|
||||||
return mT;
|
return mT;
|
||||||
|
|||||||
@@ -0,0 +1,193 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.common;
|
||||||
|
|
||||||
|
import static android.view.Display.DEFAULT_DISPLAY;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.ArgumentMatchers.notNull;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
import android.view.IDisplayWindowInsetsController;
|
||||||
|
import android.view.IWindowManager;
|
||||||
|
import android.view.InsetsSourceControl;
|
||||||
|
import android.view.InsetsState;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import com.android.wm.shell.TestShellExecutor;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public class DisplayInsetsControllerTest {
|
||||||
|
|
||||||
|
private static final int SECOND_DISPLAY = DEFAULT_DISPLAY + 10;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private IWindowManager mWm;
|
||||||
|
@Mock
|
||||||
|
private DisplayController mDisplayController;
|
||||||
|
private DisplayInsetsController mController;
|
||||||
|
private SparseArray<IDisplayWindowInsetsController> mInsetsControllersByDisplayId;
|
||||||
|
private TestShellExecutor mExecutor;
|
||||||
|
|
||||||
|
private ArgumentCaptor<Integer> mDisplayIdCaptor;
|
||||||
|
private ArgumentCaptor<IDisplayWindowInsetsController> mInsetsControllerCaptor;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
mExecutor = new TestShellExecutor();
|
||||||
|
mInsetsControllersByDisplayId = new SparseArray<>();
|
||||||
|
mDisplayIdCaptor = ArgumentCaptor.forClass(Integer.class);
|
||||||
|
mInsetsControllerCaptor = ArgumentCaptor.forClass(IDisplayWindowInsetsController.class);
|
||||||
|
mController = new DisplayInsetsController(mWm, mDisplayController, mExecutor);
|
||||||
|
addDisplay(DEFAULT_DISPLAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnDisplayAdded_setsDisplayWindowInsetsControllerOnWMService()
|
||||||
|
throws RemoteException {
|
||||||
|
addDisplay(SECOND_DISPLAY);
|
||||||
|
|
||||||
|
verify(mWm).setDisplayWindowInsetsController(eq(SECOND_DISPLAY), notNull());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnDisplayRemoved_unsetsDisplayWindowInsetsControllerInWMService()
|
||||||
|
throws RemoteException {
|
||||||
|
addDisplay(SECOND_DISPLAY);
|
||||||
|
removeDisplay(SECOND_DISPLAY);
|
||||||
|
|
||||||
|
verify(mWm).setDisplayWindowInsetsController(SECOND_DISPLAY, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPerDisplayListenerCallback() throws RemoteException {
|
||||||
|
TrackedListener defaultListener = new TrackedListener();
|
||||||
|
TrackedListener secondListener = new TrackedListener();
|
||||||
|
addDisplay(SECOND_DISPLAY);
|
||||||
|
mController.addInsetsChangedListener(DEFAULT_DISPLAY, defaultListener);
|
||||||
|
mController.addInsetsChangedListener(SECOND_DISPLAY, secondListener);
|
||||||
|
|
||||||
|
mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).topFocusedWindowChanged(null);
|
||||||
|
mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).insetsChanged(null);
|
||||||
|
mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).insetsControlChanged(null, null);
|
||||||
|
mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).showInsets(0, false);
|
||||||
|
mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).hideInsets(0, false);
|
||||||
|
mExecutor.flushAll();
|
||||||
|
|
||||||
|
assertTrue(defaultListener.topFocusedWindowChangedCount == 1);
|
||||||
|
assertTrue(defaultListener.insetsChangedCount == 1);
|
||||||
|
assertTrue(defaultListener.insetsControlChangedCount == 1);
|
||||||
|
assertTrue(defaultListener.showInsetsCount == 1);
|
||||||
|
assertTrue(defaultListener.hideInsetsCount == 1);
|
||||||
|
|
||||||
|
assertTrue(secondListener.topFocusedWindowChangedCount == 0);
|
||||||
|
assertTrue(secondListener.insetsChangedCount == 0);
|
||||||
|
assertTrue(secondListener.insetsControlChangedCount == 0);
|
||||||
|
assertTrue(secondListener.showInsetsCount == 0);
|
||||||
|
assertTrue(secondListener.hideInsetsCount == 0);
|
||||||
|
|
||||||
|
mInsetsControllersByDisplayId.get(SECOND_DISPLAY).topFocusedWindowChanged(null);
|
||||||
|
mInsetsControllersByDisplayId.get(SECOND_DISPLAY).insetsChanged(null);
|
||||||
|
mInsetsControllersByDisplayId.get(SECOND_DISPLAY).insetsControlChanged(null, null);
|
||||||
|
mInsetsControllersByDisplayId.get(SECOND_DISPLAY).showInsets(0, false);
|
||||||
|
mInsetsControllersByDisplayId.get(SECOND_DISPLAY).hideInsets(0, false);
|
||||||
|
mExecutor.flushAll();
|
||||||
|
|
||||||
|
assertTrue(defaultListener.topFocusedWindowChangedCount == 1);
|
||||||
|
assertTrue(defaultListener.insetsChangedCount == 1);
|
||||||
|
assertTrue(defaultListener.insetsControlChangedCount == 1);
|
||||||
|
assertTrue(defaultListener.showInsetsCount == 1);
|
||||||
|
assertTrue(defaultListener.hideInsetsCount == 1);
|
||||||
|
|
||||||
|
assertTrue(secondListener.topFocusedWindowChangedCount == 1);
|
||||||
|
assertTrue(secondListener.insetsChangedCount == 1);
|
||||||
|
assertTrue(secondListener.insetsControlChangedCount == 1);
|
||||||
|
assertTrue(secondListener.showInsetsCount == 1);
|
||||||
|
assertTrue(secondListener.hideInsetsCount == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addDisplay(int displayId) throws RemoteException {
|
||||||
|
mController.onDisplayAdded(displayId);
|
||||||
|
verify(mWm, times(mInsetsControllersByDisplayId.size() + 1))
|
||||||
|
.setDisplayWindowInsetsController(mDisplayIdCaptor.capture(),
|
||||||
|
mInsetsControllerCaptor.capture());
|
||||||
|
List<Integer> displayIds = mDisplayIdCaptor.getAllValues();
|
||||||
|
List<IDisplayWindowInsetsController> insetsControllers =
|
||||||
|
mInsetsControllerCaptor.getAllValues();
|
||||||
|
for (int i = 0; i < displayIds.size(); i++) {
|
||||||
|
mInsetsControllersByDisplayId.put(displayIds.get(i), insetsControllers.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeDisplay(int displayId) {
|
||||||
|
mController.onDisplayRemoved(displayId);
|
||||||
|
mInsetsControllersByDisplayId.remove(displayId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TrackedListener implements
|
||||||
|
DisplayInsetsController.OnInsetsChangedListener {
|
||||||
|
int topFocusedWindowChangedCount = 0;
|
||||||
|
int insetsChangedCount = 0;
|
||||||
|
int insetsControlChangedCount = 0;
|
||||||
|
int showInsetsCount = 0;
|
||||||
|
int hideInsetsCount = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void topFocusedWindowChanged(String packageName) {
|
||||||
|
topFocusedWindowChangedCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insetsChanged(InsetsState insetsState) {
|
||||||
|
insetsChangedCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insetsControlChanged(InsetsState insetsState,
|
||||||
|
InsetsSourceControl[] activeControls) {
|
||||||
|
insetsControlChangedCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showInsets(int types, boolean fromIme) {
|
||||||
|
showInsetsCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void hideInsets(int types, boolean fromIme) {
|
||||||
|
hideInsetsCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -685,6 +685,7 @@ public class ShellTransitionTests {
|
|||||||
// No remote stuff happening, so this can't be hit
|
// No remote stuff happening, so this can't be hit
|
||||||
}
|
}
|
||||||
DisplayController out = new DisplayController(mContext, mockWM, mMainExecutor);
|
DisplayController out = new DisplayController(mContext, mockWM, mMainExecutor);
|
||||||
|
out.initialize();
|
||||||
try {
|
try {
|
||||||
displayListener[0].onDisplayAdded(DEFAULT_DISPLAY);
|
displayListener[0].onDisplayAdded(DEFAULT_DISPLAY);
|
||||||
mMainExecutor.flushAll();
|
mMainExecutor.flushAll();
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.android.systemui.dagger.WMSingleton;
|
|||||||
import com.android.wm.shell.ShellTaskOrganizer;
|
import com.android.wm.shell.ShellTaskOrganizer;
|
||||||
import com.android.wm.shell.common.DisplayController;
|
import com.android.wm.shell.common.DisplayController;
|
||||||
import com.android.wm.shell.common.DisplayImeController;
|
import com.android.wm.shell.common.DisplayImeController;
|
||||||
|
import com.android.wm.shell.common.DisplayInsetsController;
|
||||||
import com.android.wm.shell.common.ShellExecutor;
|
import com.android.wm.shell.common.ShellExecutor;
|
||||||
import com.android.wm.shell.common.SyncTransactionQueue;
|
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||||
import com.android.wm.shell.common.SystemWindows;
|
import com.android.wm.shell.common.SystemWindows;
|
||||||
@@ -58,10 +59,10 @@ public class TvWMShellModule {
|
|||||||
@WMSingleton
|
@WMSingleton
|
||||||
@Provides
|
@Provides
|
||||||
static DisplayImeController provideDisplayImeController(IWindowManager wmService,
|
static DisplayImeController provideDisplayImeController(IWindowManager wmService,
|
||||||
DisplayController displayController, @ShellMainThread ShellExecutor mainExecutor,
|
DisplayController displayController, DisplayInsetsController displayInsetsController,
|
||||||
TransactionPool transactionPool) {
|
@ShellMainThread ShellExecutor mainExecutor, TransactionPool transactionPool) {
|
||||||
return new DisplayImeController(wmService, displayController, mainExecutor,
|
return new DisplayImeController(wmService, displayController, displayInsetsController,
|
||||||
transactionPool);
|
mainExecutor, transactionPool);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import com.android.wm.shell.bubbles.BubbleController;
|
|||||||
import com.android.wm.shell.bubbles.Bubbles;
|
import com.android.wm.shell.bubbles.Bubbles;
|
||||||
import com.android.wm.shell.common.DisplayController;
|
import com.android.wm.shell.common.DisplayController;
|
||||||
import com.android.wm.shell.common.DisplayImeController;
|
import com.android.wm.shell.common.DisplayImeController;
|
||||||
|
import com.android.wm.shell.common.DisplayInsetsController;
|
||||||
import com.android.wm.shell.common.DisplayLayout;
|
import com.android.wm.shell.common.DisplayLayout;
|
||||||
import com.android.wm.shell.common.FloatingContentCoordinator;
|
import com.android.wm.shell.common.FloatingContentCoordinator;
|
||||||
import com.android.wm.shell.common.ShellExecutor;
|
import com.android.wm.shell.common.ShellExecutor;
|
||||||
@@ -108,6 +109,14 @@ public abstract class WMShellBaseModule {
|
|||||||
return new DisplayController(context, wmService, mainExecutor);
|
return new DisplayController(context, wmService, mainExecutor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WMSingleton
|
||||||
|
@Provides
|
||||||
|
static DisplayInsetsController provideDisplayInsetsController( IWindowManager wmService,
|
||||||
|
DisplayController displayController,
|
||||||
|
@ShellMainThread ShellExecutor mainExecutor) {
|
||||||
|
return new DisplayInsetsController(wmService, displayController, mainExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
@WMSingleton
|
@WMSingleton
|
||||||
@Provides
|
@Provides
|
||||||
static DisplayLayout provideDisplayLayout() {
|
static DisplayLayout provideDisplayLayout() {
|
||||||
@@ -452,7 +461,9 @@ public abstract class WMShellBaseModule {
|
|||||||
|
|
||||||
@WMSingleton
|
@WMSingleton
|
||||||
@Provides
|
@Provides
|
||||||
static ShellInitImpl provideShellInitImpl(DisplayImeController displayImeController,
|
static ShellInitImpl provideShellInitImpl(DisplayController displayController,
|
||||||
|
DisplayImeController displayImeController,
|
||||||
|
DisplayInsetsController displayInsetsController,
|
||||||
DragAndDropController dragAndDropController,
|
DragAndDropController dragAndDropController,
|
||||||
ShellTaskOrganizer shellTaskOrganizer,
|
ShellTaskOrganizer shellTaskOrganizer,
|
||||||
Optional<BubbleController> bubblesOptional,
|
Optional<BubbleController> bubblesOptional,
|
||||||
@@ -465,7 +476,9 @@ public abstract class WMShellBaseModule {
|
|||||||
Transitions transitions,
|
Transitions transitions,
|
||||||
StartingWindowController startingWindow,
|
StartingWindowController startingWindow,
|
||||||
@ShellMainThread ShellExecutor mainExecutor) {
|
@ShellMainThread ShellExecutor mainExecutor) {
|
||||||
return new ShellInitImpl(displayImeController,
|
return new ShellInitImpl(displayController,
|
||||||
|
displayImeController,
|
||||||
|
displayInsetsController,
|
||||||
dragAndDropController,
|
dragAndDropController,
|
||||||
shellTaskOrganizer,
|
shellTaskOrganizer,
|
||||||
bubblesOptional,
|
bubblesOptional,
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import com.android.wm.shell.WindowManagerShellWrapper;
|
|||||||
import com.android.wm.shell.apppairs.AppPairsController;
|
import com.android.wm.shell.apppairs.AppPairsController;
|
||||||
import com.android.wm.shell.common.DisplayController;
|
import com.android.wm.shell.common.DisplayController;
|
||||||
import com.android.wm.shell.common.DisplayImeController;
|
import com.android.wm.shell.common.DisplayImeController;
|
||||||
|
import com.android.wm.shell.common.DisplayInsetsController;
|
||||||
import com.android.wm.shell.common.FloatingContentCoordinator;
|
import com.android.wm.shell.common.FloatingContentCoordinator;
|
||||||
import com.android.wm.shell.common.ShellExecutor;
|
import com.android.wm.shell.common.ShellExecutor;
|
||||||
import com.android.wm.shell.common.SyncTransactionQueue;
|
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||||
@@ -83,10 +84,11 @@ public class WMShellModule {
|
|||||||
@WMSingleton
|
@WMSingleton
|
||||||
@Provides
|
@Provides
|
||||||
static DisplayImeController provideDisplayImeController(IWindowManager wmService,
|
static DisplayImeController provideDisplayImeController(IWindowManager wmService,
|
||||||
DisplayController displayController, @ShellMainThread ShellExecutor mainExecutor,
|
DisplayController displayController, DisplayInsetsController displayInsetsController,
|
||||||
|
@ShellMainThread ShellExecutor mainExecutor,
|
||||||
TransactionPool transactionPool) {
|
TransactionPool transactionPool) {
|
||||||
return new DisplayImeController(wmService, displayController, mainExecutor,
|
return new DisplayImeController(wmService, displayController, displayInsetsController,
|
||||||
transactionPool);
|
mainExecutor, transactionPool);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
Reference in New Issue
Block a user