Refine logic about controlling transient bars

- Use copied InsetsSourceControl to prevent the leash from being
  released while the control gets revoked while playing transient
  bar animations.
- Start the animation after mAnimationControl gets assigned to prevent
  NullPointerException.
- Let SystemUI to change the bar mode to transient mode before WM
  plays the transient bar animation.
- Remove a redundunt call to the super method.
- Fix InsetsPolicyTest
- Fix InsetsStateControllerTest
- Fix misc things

Bug: 118118435
Test: Manually swipe to show transient bars many times.
Test: atest InsetsSourceProviderTest InsetsStateControllerTest
            InsetsPolicyTest WindowStateTests CommandQueueTest
            RegisterStatusBarResultTest InsetsFlagsTest
            LightBarControllerTest RegisterStatusBarResultTest
            ViewRootImplTest DisplayPolicyInsetsTests
            DisplayPolicyTests TaskSnapshotSurfaceTest
            InsetsAnimationControlImplTest
Change-Id: I7d445b7dc6f47a64048937cd439bdd5ffa7fa3a3
This commit is contained in:
Tiger Huang
2020-02-05 17:10:03 +08:00
parent be5015b00a
commit a166340304
6 changed files with 64 additions and 42 deletions

View File

@@ -198,7 +198,7 @@ public class InsetsSource implements Parcelable {
return "InsetsSource: {"
+ "mType=" + InsetsState.typeToString(mType)
+ ", mFrame=" + mFrame.toShortString()
+ ", mVisible" + mVisible
+ ", mVisible=" + mVisible
+ "}";
}

View File

@@ -16,8 +16,6 @@
package android.view;
import static android.view.WindowInsets.Type.ime;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -148,7 +146,7 @@ public interface WindowInsetsController {
* @param types The {@link InsetsType}s the application has requested to control.
* @param durationMillis Duration of animation in
* {@link java.util.concurrent.TimeUnit#MILLISECONDS}, or -1 if the
* animation doesn't have a predetermined duration.T his value will be
* animation doesn't have a predetermined duration. This value will be
* passed to {@link InsetsAnimation#getDurationMillis()}
* @param interpolator The interpolator used for this animation, or {@code null} if this
* animation doesn't follow an interpolation curve. This value will be

View File

@@ -44,6 +44,7 @@ import android.view.ViewRootImpl;
import android.view.WindowInsetsAnimationCallback;
import android.view.WindowInsetsAnimationControlListener;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.DisplayThread;
/**
@@ -107,11 +108,11 @@ class InsetsPolicy {
changed = true;
}
if (changed) {
startAnimation(mShowingTransientTypes, true, () -> {
mPolicy.getStatusBarManagerInternal().showTransient(mDisplayContent.getDisplayId(),
mShowingTransientTypes.toArray());
updateBarControlTarget(mFocusedWin);
startAnimation(true /* show */, () -> {
synchronized (mDisplayContent.mWmService.mGlobalLock) {
mPolicy.getStatusBarManagerInternal().showTransient(
mDisplayContent.getDisplayId(),
mShowingTransientTypes.toArray());
mStateController.notifyInsetsChanged();
}
});
@@ -122,7 +123,7 @@ class InsetsPolicy {
if (mShowingTransientTypes.size() == 0) {
return;
}
startAnimation(mShowingTransientTypes, false, () -> {
startAnimation(false /* show */, () -> {
synchronized (mDisplayContent.mWmService.mGlobalLock) {
mShowingTransientTypes.clear();
mStateController.notifyInsetsChanged();
@@ -268,18 +269,20 @@ class InsetsPolicy {
return isDockedStackVisible || isFreeformStackVisible || isResizing;
}
private void startAnimation(IntArray internalTypes, boolean show, Runnable callback) {
@VisibleForTesting
void startAnimation(boolean show, Runnable callback) {
int typesReady = 0;
final SparseArray<InsetsSourceControl> controls = new SparseArray<>();
updateBarControlTarget(mFocusedWin);
for (int i = internalTypes.size() - 1; i >= 0; i--) {
final IntArray showingTransientTypes = mShowingTransientTypes;
for (int i = showingTransientTypes.size() - 1; i >= 0; i--) {
InsetsSourceProvider provider =
mStateController.getSourceProvider(internalTypes.get(i));
if (provider == null) continue;
InsetsSourceControl control = provider.getControl(provider.getControlTarget());
if (control == null || control.getLeash() == null) continue;
typesReady |= InsetsState.toPublicType(internalTypes.get(i));
controls.put(control.getType(), control);
mStateController.getSourceProvider(showingTransientTypes.get(i));
InsetsSourceControl control = provider.getControl(mTransientControlTarget);
if (control == null || control.getLeash() == null) {
continue;
}
typesReady |= InsetsState.toPublicType(showingTransientTypes.get(i));
controls.put(control.getType(), new InsetsSourceControl(control));
}
controlAnimationUnchecked(typesReady, controls, show, callback);
}
@@ -335,7 +338,6 @@ class InsetsPolicy {
private InsetsPolicyAnimationControlListener mListener;
InsetsPolicyAnimationControlCallbacks(InsetsPolicyAnimationControlListener listener) {
super();
mListener = listener;
}
@@ -353,9 +355,11 @@ class InsetsPolicy {
InsetsController.INTERPOLATOR, true,
show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
: LAYOUT_INSETS_DURING_ANIMATION_HIDDEN);
SurfaceAnimationThread.getHandler().post(
() -> mListener.onReady(mAnimationControl, typesReady));
}
/** Called on SurfaceAnimationThread lock without global WM lock held. */
/** Called on SurfaceAnimationThread without global WM lock held. */
@Override
public void scheduleApplyChangeInsets() {
InsetsState state = getState();
@@ -384,7 +388,7 @@ class InsetsPolicy {
return overrideState;
}
/** Called on SurfaceAnimationThread lock without global WM lock held. */
/** Called on SurfaceAnimationThread without global WM lock held. */
@Override
public void applySurfaceParams(
final SyncRtSurfaceTransactionApplier.SurfaceParams... params) {
@@ -396,14 +400,12 @@ class InsetsPolicy {
t.apply();
}
/** Called on SurfaceAnimationThread lock without global WM lock held. */
@Override
public void startAnimation(InsetsAnimationControlImpl controller,
WindowInsetsAnimationControlListener listener, int types,
WindowInsetsAnimationCallback.InsetsAnimation animation,
WindowInsetsAnimationCallback.AnimationBounds bounds,
int layoutDuringAnimation) {
SurfaceAnimationThread.getHandler().post(() -> listener.onReady(controller, types));
}
}
}

View File

@@ -16,6 +16,7 @@
package com.android.server.wm;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
@@ -89,6 +90,12 @@ class InsetsStateController {
if (type == ITYPE_NAVIGATION_BAR) {
state.removeSource(ITYPE_IME);
state.removeSource(ITYPE_STATUS_BAR);
state.removeSource(ITYPE_CAPTION_BAR);
}
// Status bar doesn't get influenced by caption bar
if (type == ITYPE_STATUS_BAR) {
state.removeSource(ITYPE_CAPTION_BAR);
}
// IME needs different frames for certain cases (e.g. navigation bar in gesture nav).
@@ -212,18 +219,18 @@ class InsetsStateController {
/**
* Called when the focused window that is able to control the system bars changes.
*
* @param topControlling The target that is now able to control the top bar appearance
* and visibility.
* @param statusControlling The target that is now able to control the status bar appearance
* and visibility.
* @param navControlling The target that is now able to control the nav bar appearance
* and visibility.
*/
void onBarControlTargetChanged(@Nullable InsetsControlTarget topControlling,
@Nullable InsetsControlTarget fakeTopControlling,
void onBarControlTargetChanged(@Nullable InsetsControlTarget statusControlling,
@Nullable InsetsControlTarget fakeStatusControlling,
@Nullable InsetsControlTarget navControlling,
@Nullable InsetsControlTarget fakeNavControlling) {
onControlChanged(ITYPE_STATUS_BAR, topControlling);
onControlChanged(ITYPE_STATUS_BAR, statusControlling);
onControlChanged(ITYPE_NAVIGATION_BAR, navControlling);
onControlFakeTargetChanged(ITYPE_STATUS_BAR, fakeTopControlling);
onControlFakeTargetChanged(ITYPE_STATUS_BAR, fakeStatusControlling);
onControlFakeTargetChanged(ITYPE_NAVIGATION_BAR, fakeNavControlling);
notifyPendingInsetsControlChanged();
}

View File

@@ -29,12 +29,13 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy;
import android.platform.test.annotations.Presubmit;
import android.util.IntArray;
@@ -122,13 +123,13 @@ public class InsetsPolicyTest extends WindowTestsBase {
// TODO: adjust this test if we pretend to the app that it's still able to control it.
@Test
public void testControlsForDispatch_forceStatusBarVisible() {
addWindow(TYPE_STATUS_BAR, "topBar").mAttrs.privateFlags |=
addWindow(TYPE_STATUS_BAR, "statusBar").mAttrs.privateFlags |=
PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
addWindow(TYPE_NAVIGATION_BAR, "navBar");
final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
// The app must not control the top bar.
// The app must not control the status bar.
assertNotNull(controls);
assertEquals(1, controls.length);
}
@@ -137,6 +138,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
public void testControlsForDispatch_statusBarForceShowNavigation() {
addWindow(TYPE_NOTIFICATION_SHADE, "notificationShade").mAttrs.privateFlags |=
PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
addWindow(TYPE_STATUS_BAR, "statusBar");
addWindow(TYPE_NAVIGATION_BAR, "navBar");
final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
@@ -169,7 +171,8 @@ public class InsetsPolicyTest extends WindowTestsBase {
.getControllableInsetProvider().getSource().setVisible(false);
final WindowState app = addWindow(TYPE_APPLICATION, "app");
final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
doNothing().when(policy).startAnimation(anyBoolean(), any());
policy.updateBarControlTarget(app);
policy.showTransient(
IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
@@ -184,7 +187,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
}
@Test
public void testShowTransientBars_topCanBeTransient_appGetsTopFakeControl() {
public void testShowTransientBars_statusBarCanBeTransient_appGetsStatusBarFakeControl() {
// Adding app window before setting source visibility is to prevent the visibility from
// being cleared by InsetsSourceProvider.updateVisibility.
final WindowState app = addWindow(TYPE_APPLICATION, "app");
@@ -194,14 +197,15 @@ public class InsetsPolicyTest extends WindowTestsBase {
addWindow(TYPE_NAVIGATION_BAR, "navBar")
.getControllableInsetProvider().getSource().setVisible(true);
final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
doNothing().when(policy).startAnimation(anyBoolean(), any());
policy.updateBarControlTarget(app);
policy.showTransient(
IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
final InsetsSourceControl[] controls =
mDisplayContent.getInsetsStateController().getControlsForDispatch(app);
// The app must get the fake control of the top bar, and must get the real control of the
// The app must get the fake control of the status bar, and must get the real control of the
// navigation bar.
assertEquals(2, controls.length);
for (int i = controls.length - 1; i >= 0; i--) {
@@ -222,7 +226,8 @@ public class InsetsPolicyTest extends WindowTestsBase {
.getControllableInsetProvider().getSource().setVisible(false);
final WindowState app = addWindow(TYPE_APPLICATION, "app");
final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
doNothing().when(policy).startAnimation(anyBoolean(), any());
policy.updateBarControlTarget(app);
policy.showTransient(
IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));

View File

@@ -20,7 +20,9 @@ import static android.view.InsetsState.ITYPE_IME;
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.FLAG_NOT_FOCUSABLE;
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;
@@ -33,14 +35,14 @@ 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
@@ -88,6 +90,10 @@ 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");
// IME cannot be the IME target.
ime.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
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);
@@ -98,6 +104,10 @@ public class InsetsStateControllerTest extends WindowTestsBase {
public void testImeForDispatch() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
// IME cannot be the IME target.
ime.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
InsetsSourceProvider statusBarProvider =
getController().getSourceProvider(ITYPE_STATUS_BAR);
statusBarProvider.setWindow(statusBar, null, ((displayFrames, windowState, rect) ->