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:
@@ -198,7 +198,7 @@ public class InsetsSource implements Parcelable {
|
||||
return "InsetsSource: {"
|
||||
+ "mType=" + InsetsState.typeToString(mType)
|
||||
+ ", mFrame=" + mFrame.toShortString()
|
||||
+ ", mVisible" + mVisible
|
||||
+ ", mVisible=" + mVisible
|
||||
+ "}";
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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}));
|
||||
|
||||
@@ -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) ->
|
||||
|
||||
Reference in New Issue
Block a user