Merge "Dispatch separate navigation bar frame to IME"

This commit is contained in:
Jorim Jaggi
2020-01-30 11:33:39 +00:00
committed by Android (Google) Code Review
7 changed files with 100 additions and 27 deletions

View File

@@ -1244,6 +1244,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
return mDisplayRotation;
}
void setInsetProvider(@InternalInsetsType int type, WindowState win,
@Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider){
setInsetProvider(type, win, frameProvider, null /* imeFrameProvider */);
}
/**
* Marks a window as providing insets for the rest of the windows in the system.
*
@@ -1251,10 +1256,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
* @param win The window.
* @param frameProvider Function to compute the frame, or {@code null} if the just the frame of
* the window should be taken.
* @param imeFrameProvider Function to compute the frame when dispatching insets to the IME, or
* {@code null} if the normal frame should be taken.
*/
void setInsetProvider(@InternalInsetsType int type, WindowState win,
@Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider) {
mInsetsStateController.getSourceProvider(type).setWindow(win, frameProvider);
@Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider,
@Nullable TriConsumer<DisplayFrames, WindowState, Rect> imeFrameProvider) {
mInsetsStateController.getSourceProvider(type).setWindow(win, frameProvider,
imeFrameProvider);
}
InsetsStateController getInsetsStateController() {
@@ -3283,7 +3292,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
computeImeTarget(true /* updateImeTarget */);
mInsetsStateController.getSourceProvider(ITYPE_IME).setWindow(win,
null /* frameProvider */);
null /* frameProvider */, null /* imeFrameProvider */);
}
/**

View File

@@ -1026,7 +1026,12 @@ public class DisplayPolicy {
- getNavigationBarHeight(displayFrames.mRotation,
mDisplayContent.getConfiguration().uiMode);
}
});
},
// For IME we use regular frame.
(displayFrames, windowState, inOutFrame) ->
inOutFrame.set(windowState.getFrameLw()));
mDisplayContent.setInsetProvider(ITYPE_BOTTOM_GESTURES, win,
(displayFrames, windowState, inOutFrame) -> {
inOutFrame.top -= mBottomGestureAdditionalInset;

View File

@@ -34,6 +34,7 @@ import android.util.proto.ProtoOutputStream;
import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
@@ -61,6 +62,8 @@ class InsetsSourceProvider {
private @Nullable ControlAdapter mAdapter;
private TriConsumer<DisplayFrames, WindowState, Rect> mFrameProvider;
private TriConsumer<DisplayFrames, WindowState, Rect> mImeFrameProvider;
private final Rect mImeOverrideFrame = new Rect();
/** The visibility override from the current controlling window. */
private boolean mClientVisible;
@@ -111,9 +114,12 @@ class InsetsSourceProvider {
* @param win The window that links to this source.
* @param frameProvider Based on display frame state and the window, calculates the resulting
* frame that should be reported to clients.
* @param imeFrameProvider Based on display frame state and the window, calculates the resulting
* frame that should be reported to IME.
*/
void setWindow(@Nullable WindowState win,
@Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider) {
@Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider,
@Nullable TriConsumer<DisplayFrames, WindowState, Rect> imeFrameProvider) {
if (mWin != null) {
if (mControllable) {
mWin.setControllableInsetProvider(null);
@@ -126,6 +132,7 @@ class InsetsSourceProvider {
}
mWin = win;
mFrameProvider = frameProvider;
mImeFrameProvider = imeFrameProvider;
if (win == null) {
setServerVisible(false);
mSource.setFrame(new Rect());
@@ -162,6 +169,12 @@ class InsetsSourceProvider {
}
mSource.setFrame(mTmpRect);
if (mImeFrameProvider != null) {
mImeOverrideFrame.set(mWin.getFrameLw());
mImeFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin,
mImeOverrideFrame);
}
if (mWin.mGivenVisibleInsets.left != 0 || mWin.mGivenVisibleInsets.top != 0
|| mWin.mGivenVisibleInsets.right != 0 || mWin.mGivenVisibleInsets.bottom != 0) {
mTmpRect.set(mWin.getFrameLw());
@@ -303,6 +316,21 @@ class InsetsSourceProvider {
return sNewInsetsMode == NEW_INSETS_MODE_NONE || mClientVisible;
}
/**
* @return Whether this provider uses a different frame to dispatch to the IME.
*/
boolean overridesImeFrame() {
return mImeFrameProvider != null;
}
/**
* @return Rect to dispatch to the IME as frame. Only valid if {@link #overridesImeFrame()}
* returns {@code true}.
*/
Rect getImeOverrideFrame() {
return mImeOverrideFrame;
}
private class ControlAdapter implements AnimationAdapter {
private SurfaceControl mCapturedLeash;

View File

@@ -88,6 +88,20 @@ class InsetsStateController {
state.removeSource(ITYPE_IME);
state.removeSource(ITYPE_STATUS_BAR);
}
// IME needs different frames for certain cases (e.g. navigation bar in gesture nav).
if (type == ITYPE_IME) {
for (int i = mProviders.size() - 1; i >= 0; i--) {
InsetsSourceProvider otherProvider = mProviders.valueAt(i);
if (otherProvider.overridesImeFrame()) {
InsetsSource override =
new InsetsSource(state.getSource(otherProvider.getSource().getType()));
override.setFrame(otherProvider.getImeOverrideFrame());
state.addSource(override);
}
}
}
return state;
}

View File

@@ -57,7 +57,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
statusBar.getFrameLw().set(0, 0, 500, 100);
statusBar.mHasSurface = true;
mProvider.setWindow(statusBar, null);
mProvider.setWindow(statusBar, null, null);
mProvider.onPostLayout();
assertEquals(new Rect(0, 0, 500, 100), mProvider.getSource().getFrame());
assertEquals(Insets.of(0, 100, 0, 0),
@@ -74,7 +74,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
ime.getGivenContentInsetsLw().set(0, 0, 0, 60);
ime.getGivenVisibleInsetsLw().set(0, 0, 0, 75);
ime.mHasSurface = true;
mProvider.setWindow(ime, null);
mProvider.setWindow(ime, null, null);
mProvider.onPostLayout();
assertEquals(new Rect(0, 0, 500, 40), mProvider.getSource().getFrame());
assertEquals(new Rect(0, 0, 500, 25), mProvider.getSource().getVisibleFrame());
@@ -89,7 +89,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
public void testPostLayout_invisible() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
statusBar.getFrameLw().set(0, 0, 500, 100);
mProvider.setWindow(statusBar, null);
mProvider.setWindow(statusBar, null, null);
mProvider.onPostLayout();
assertEquals(Insets.NONE, mProvider.getSource().calculateInsets(new Rect(0, 0, 500, 500),
false /* ignoreVisibility */));
@@ -102,7 +102,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
mProvider.setWindow(statusBar,
(displayFrames, windowState, rect) -> {
rect.set(10, 10, 20, 20);
});
}, null);
mProvider.onPostLayout();
assertEquals(new Rect(10, 10, 20, 20), mProvider.getSource().getFrame());
}
@@ -112,7 +112,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
statusBar.getFrameLw().set(0, 0, 500, 100);
mProvider.setWindow(statusBar, null);
mProvider.setWindow(statusBar, null, null);
mProvider.updateControlForTarget(target, false /* force */);
assertNotNull(mProvider.getControl(target));
mProvider.updateControlForTarget(null, false /* force */);
@@ -124,7 +124,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
statusBar.getFrameLw().set(0, 0, 500, 100);
mProvider.setWindow(statusBar, null);
mProvider.setWindow(statusBar, null, null);
mProvider.updateControlForFakeTarget(target);
assertNotNull(mProvider.getControl(target));
assertNull(mProvider.getControl(target).getLeash());
@@ -137,7 +137,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
statusBar.getFrameLw().set(0, 0, 500, 100);
mProvider.setWindow(statusBar, null);
mProvider.setWindow(statusBar, null, null);
mProvider.updateControlForTarget(target, false /* force */);
InsetsState state = new InsetsState();
state.getSource(ITYPE_STATUS_BAR).setVisible(false);
@@ -150,7 +150,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
statusBar.getFrameLw().set(0, 0, 500, 100);
mProvider.setWindow(statusBar, null);
mProvider.setWindow(statusBar, null, null);
InsetsState state = new InsetsState();
state.getSource(ITYPE_STATUS_BAR).setVisible(false);
mProvider.onInsetsModified(target, state.getSource(ITYPE_STATUS_BAR));

View File

@@ -21,26 +21,26 @@ import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.test.InsetsModeSession;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
@SmallTest
@FlakyTest(detail = "Promote to pre-submit once confirmed stable.")
@Presubmit
@@ -65,7 +65,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
public void testStripForDispatch_notOwn() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null);
getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
statusBar.setControllableInsetProvider(getController().getSourceProvider(ITYPE_STATUS_BAR));
assertNotNull(getController().getInsetsForDispatch(app).getSource(ITYPE_STATUS_BAR));
}
@@ -74,7 +74,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
public void testStripForDispatch_own() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_STATUS_BAR)
.setWindow(statusBar, null);
.setWindow(statusBar, null, null);
statusBar.setControllableInsetProvider(getController().getSourceProvider(ITYPE_STATUS_BAR));
final InsetsState state = getController().getInsetsForDispatch(statusBar);
for (int i = state.getSourcesCount() - 1; i >= 0; i--) {
@@ -88,19 +88,36 @@ public class InsetsStateControllerTest extends WindowTestsBase {
final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null);
getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null);
getController().getSourceProvider(ITYPE_IME).setWindow(ime, null);
getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
assertEquals(0, getController().getInsetsForDispatch(navBar).getSourcesCount());
}
@Test
public void testImeForDispatch() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
InsetsSourceProvider statusBarProvider =
getController().getSourceProvider(ITYPE_STATUS_BAR);
statusBarProvider.setWindow(statusBar, null, ((displayFrames, windowState, rect) ->
rect.set(0, 1, 2, 3)));
getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
statusBar.setControllableInsetProvider(statusBarProvider);
statusBarProvider.onPostLayout();
final InsetsState state = getController().getInsetsForDispatch(ime);
assertEquals(new Rect(0, 1, 2, 3), state.getSource(ITYPE_STATUS_BAR).getFrame());
}
@Test
public void testBarControllingWinChanged() {
final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null);
getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null);
getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
getController().onBarControlTargetChanged(app, null, app, null);
InsetsSourceControl[] controls = getController().getControlsForDispatch(app);
assertEquals(2, controls.length);
@@ -110,7 +127,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
public void testControlRevoked() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null);
getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
getController().onBarControlTargetChanged(app, null, null, null);
assertNotNull(getController().getControlsForDispatch(app));
getController().onBarControlTargetChanged(null, null, null, null);
@@ -122,7 +139,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
public void testControlRevoked_animation() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null);
getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
getController().onBarControlTargetChanged(app, null, null, null);
assertNotNull(getController().getControlsForDispatch(app));
statusBar.cancelAnimation();

View File

@@ -425,7 +425,7 @@ public class WindowStateTests extends WindowTestsBase {
statusBar.mHasSurface = true;
assertTrue(statusBar.isVisible());
mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_STATUS_BAR)
.setWindow(statusBar, null /* frameProvider */);
.setWindow(statusBar, null /* frameProvider */, null /* imeFrameProvider */);
mDisplayContent.getInsetsStateController().onBarControlTargetChanged(
app, null /* fakeTopControlling */, app, null /* fakeNavControlling */);
final InsetsSource source = new InsetsSource(ITYPE_STATUS_BAR);