Loading services/core/java/com/android/server/wm/Dimmer.java +170 −29 Original line number Diff line number Diff line Loading @@ -17,34 +17,115 @@ package com.android.server.wm; import android.util.ArrayMap; import android.util.Slog; import android.view.SurfaceControl; import android.graphics.Rect; import com.android.internal.annotations.VisibleForTesting; /** * Utility class for use by a WindowContainer implementation to add "DimLayer" support, that is * black layers of varying opacity at various Z-levels which create the effect of a Dim. */ class Dimmer { private static final String TAG = "WindowManager"; private static final int DEFAULT_DIM_ANIM_DURATION = 200; private class DimAnimatable implements SurfaceAnimator.Animatable { private final SurfaceControl mDimLayer; private DimAnimatable(SurfaceControl dimLayer) { mDimLayer = dimLayer; } @Override public SurfaceControl.Transaction getPendingTransaction() { return mHost.getPendingTransaction(); } @Override public void commitPendingTransaction() { mHost.commitPendingTransaction(); } @Override public void onAnimationLeashCreated(SurfaceControl.Transaction t, SurfaceControl leash) { } @Override public void onAnimationLeashDestroyed(SurfaceControl.Transaction t) { } @Override public void destroyAfterPendingTransaction(SurfaceControl surface) { mHost.destroyAfterPendingTransaction(surface); } @Override public SurfaceControl.Builder makeAnimationLeash() { return mHost.makeAnimationLeash(); } @Override public SurfaceControl getAnimationLeashParent() { return mHost.getSurfaceControl(); } @Override public SurfaceControl getSurfaceControl() { return mDimLayer; } @Override public SurfaceControl getParentSurfaceControl() { return mHost.getSurfaceControl(); } @Override public int getSurfaceWidth() { // This will determine the size of the leash created. This should be the size of the // host and not the dim layer since the dim layer may get bigger during animation. If // that occurs, the leash size cannot change so we need to ensure the leash is big // enough that the dim layer can grow. // This works because the mHost will be a Task which has the display bounds. return mHost.getSurfaceWidth(); } @Override public int getSurfaceHeight() { // See getSurfaceWidth() above for explanation. return mHost.getSurfaceHeight(); } } private class DimState { SurfaceControl mSurfaceControl; @VisibleForTesting class DimState { /** * The layer where property changes should be invoked on. */ SurfaceControl mDimLayer; boolean mDimming; boolean isVisible; SurfaceAnimator mSurfaceAnimator; /** * Used for Dims not assosciated with a WindowContainer. See {@link Dimmer#dimAbove} for * Used for Dims not associated with a WindowContainer. See {@link Dimmer#dimAbove} for * details on Dim lifecycle. */ boolean mDontReset; DimState(SurfaceControl ctl) { mSurfaceControl = ctl; DimState(SurfaceControl dimLayer) { mDimLayer = dimLayer; mDimming = true; mSurfaceAnimator = new SurfaceAnimator(new DimAnimatable(dimLayer), () -> { if (!mDimming) { mDimLayer.destroy(); } }, mHost.mService.mAnimator::addAfterPrepareSurfacesRunnable, mHost.mService); } } }; private ArrayMap<WindowContainer, DimState> mDimLayerUsers = new ArrayMap<>(); @VisibleForTesting ArrayMap<WindowContainer, DimState> mDimLayerUsers = new ArrayMap<>(); /** * The {@link WindowContainer} that our Dim's are bounded to. We may be dimming on behalf of the Loading @@ -56,19 +137,18 @@ class Dimmer { mHost = host; } SurfaceControl makeDimLayer() { final SurfaceControl control = mHost.makeChildSurface(null) private SurfaceControl makeDimLayer() { return mHost.makeChildSurface(null) .setParent(mHost.getSurfaceControl()) .setColorLayer(true) .setName("Dim Layer for - " + mHost.getName()) .build(); return control; } /** * Retreive the DimState for a given child of the host. */ DimState getDimState(WindowContainer container) { private DimState getDimState(WindowContainer container) { DimState state = mDimLayerUsers.get(container); if (state == null) { final SurfaceControl ctl = makeDimLayer(); Loading @@ -88,14 +168,12 @@ class Dimmer { private void dim(SurfaceControl.Transaction t, WindowContainer container, int relativeLayer, float alpha) { final DimState d = getDimState(container); t.show(d.mSurfaceControl); if (container != null) { t.setRelativeLayer(d.mSurfaceControl, container.getSurfaceControl(), relativeLayer); t.setRelativeLayer(d.mDimLayer, container.getSurfaceControl(), relativeLayer); } else { t.setLayer(d.mSurfaceControl, Integer.MAX_VALUE); t.setLayer(d.mDimLayer, Integer.MAX_VALUE); } t.setAlpha(d.mSurfaceControl, alpha); t.setAlpha(d.mDimLayer, alpha); d.mDimming = true; } Loading @@ -107,9 +185,11 @@ class Dimmer { */ void stopDim(SurfaceControl.Transaction t) { DimState d = getDimState(null); t.hide(d.mSurfaceControl); t.hide(d.mDimLayer); d.isVisible = false; d.mDontReset = false; } /** * Place a Dim above the entire host container. The caller is responsible for calling stopDim to * remove this effect. If the Dim can be assosciated with a particular child of the host Loading Loading @@ -159,7 +239,7 @@ class Dimmer { void resetDimStates() { for (int i = mDimLayerUsers.size() - 1; i >= 0; i--) { final DimState state = mDimLayerUsers.valueAt(i); if (state.mDontReset == false) { if (!state.mDontReset) { state.mDimming = false; } } Loading @@ -177,19 +257,80 @@ class Dimmer { boolean didSomething = false; for (int i = mDimLayerUsers.size() - 1; i >= 0; i--) { DimState state = mDimLayerUsers.valueAt(i); WindowContainer container = mDimLayerUsers.keyAt(i); // TODO: We want to animate the addition and removal of Dim's instead of immediately // acting. When we do this we need to take care to account for the "Replacing Windows" // case (and seamless dim transfer). if (state.mDimming == false) { if (!state.mDimming) { mDimLayerUsers.removeAt(i); state.mSurfaceControl.destroy(); startDimExit(container, state.mSurfaceAnimator, t); } else { didSomething = true; // TODO: Once we use geometry from hierarchy this falls away. t.setSize(state.mSurfaceControl, bounds.width(), bounds.height()); t.setPosition(state.mSurfaceControl, bounds.left, bounds.top); t.setSize(state.mDimLayer, bounds.width(), bounds.height()); t.setPosition(state.mDimLayer, bounds.left, bounds.top); if (!state.isVisible) { state.isVisible = true; t.show(state.mDimLayer); startDimEnter(container, state.mSurfaceAnimator, t); } } } return didSomething; } private void startDimEnter(WindowContainer container, SurfaceAnimator animator, SurfaceControl.Transaction t) { startAnim(container, animator, t, 0 /* startAlpha */, 1 /* endAlpha */); } private void startDimExit(WindowContainer container, SurfaceAnimator animator, SurfaceControl.Transaction t) { startAnim(container, animator, t, 1 /* startAlpha */, 0 /* endAlpha */); } private void startAnim(WindowContainer container, SurfaceAnimator animator, SurfaceControl.Transaction t, float startAlpha, float endAlpha) { animator.startAnimation(t, new LocalAnimationAdapter( new AlphaAnimationSpec(startAlpha, endAlpha, getDimDuration(container)), mHost.mService.mSurfaceAnimationRunner), false /* hidden */); } private long getDimDuration(WindowContainer container) { // If there's no container, then there isn't an animation occurring while dimming. Set the // duration to 0 so it immediately dims to the set alpha. if (container == null) { return 0; } // Otherwise use the same duration as the animation on the WindowContainer AnimationAdapter animationAdapter = container.mSurfaceAnimator.getAnimation(); return animationAdapter == null ? DEFAULT_DIM_ANIM_DURATION : animationAdapter.getDurationHint(); } private static class AlphaAnimationSpec implements LocalAnimationAdapter.AnimationSpec { private final long mDuration; private final float mFromAlpha; private final float mToAlpha; AlphaAnimationSpec(float fromAlpha, float toAlpha, long duration) { mFromAlpha = fromAlpha; mToAlpha = toAlpha; mDuration = duration; } @Override public long getDuration() { return mDuration; } @Override public void apply(SurfaceControl.Transaction t, SurfaceControl sc, long currentPlayTime) { float alpha = ((float) currentPlayTime / getDuration()) * (mToAlpha - mFromAlpha) + mFromAlpha; t.setAlpha(sc, alpha); } } } services/core/java/com/android/server/wm/DisplayContent.java +18 −0 Original line number Diff line number Diff line Loading @@ -3599,6 +3599,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } private final class AboveAppWindowContainers extends NonAppWindowContainers { private final Dimmer mDimmer = new Dimmer(this); private final Rect mTmpDimBoundsRect = new Rect(); AboveAppWindowContainers(String name, WindowManagerService service) { super(name, service); } Loading Loading @@ -3630,6 +3632,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo imeContainer.assignRelativeLayer(t, getSurfaceControl(), Integer.MAX_VALUE); } } @Override Dimmer getDimmer() { return mDimmer; } @Override void prepareSurfaces() { mDimmer.resetDimStates(); super.prepareSurfaces(); getBounds(mTmpDimBoundsRect); if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) { scheduleAnimation(); } } } /** Loading services/core/java/com/android/server/wm/Task.java +2 −1 Original line number Diff line number Diff line Loading @@ -462,8 +462,8 @@ class Task extends WindowContainer<AppWindowToken> { } else { mStack.getBounds(mTmpRect); mTmpRect.intersect(getBounds()); } out.set(mTmpRect); } } else { out.set(getBounds()); } Loading Loading @@ -640,6 +640,7 @@ class Task extends WindowContainer<AppWindowToken> { mPreserveNonFloatingState = false; } @Override Dimmer getDimmer() { return mDimmer; } Loading services/core/java/com/android/server/wm/TaskStack.java +1 −0 Original line number Diff line number Diff line Loading @@ -1722,6 +1722,7 @@ public class TaskStack extends WindowContainer<Task> implements || activityType == ACTIVITY_TYPE_ASSISTANT; } @Override Dimmer getDimmer() { return mDimmer; } Loading services/core/java/com/android/server/wm/WindowContainer.java +7 −0 Original line number Diff line number Diff line Loading @@ -1231,4 +1231,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< outPos.offset(-parentBounds.left, -parentBounds.top); } } Dimmer getDimmer() { if (mParent == null) { return null; } return mParent.getDimmer(); } } Loading
services/core/java/com/android/server/wm/Dimmer.java +170 −29 Original line number Diff line number Diff line Loading @@ -17,34 +17,115 @@ package com.android.server.wm; import android.util.ArrayMap; import android.util.Slog; import android.view.SurfaceControl; import android.graphics.Rect; import com.android.internal.annotations.VisibleForTesting; /** * Utility class for use by a WindowContainer implementation to add "DimLayer" support, that is * black layers of varying opacity at various Z-levels which create the effect of a Dim. */ class Dimmer { private static final String TAG = "WindowManager"; private static final int DEFAULT_DIM_ANIM_DURATION = 200; private class DimAnimatable implements SurfaceAnimator.Animatable { private final SurfaceControl mDimLayer; private DimAnimatable(SurfaceControl dimLayer) { mDimLayer = dimLayer; } @Override public SurfaceControl.Transaction getPendingTransaction() { return mHost.getPendingTransaction(); } @Override public void commitPendingTransaction() { mHost.commitPendingTransaction(); } @Override public void onAnimationLeashCreated(SurfaceControl.Transaction t, SurfaceControl leash) { } @Override public void onAnimationLeashDestroyed(SurfaceControl.Transaction t) { } @Override public void destroyAfterPendingTransaction(SurfaceControl surface) { mHost.destroyAfterPendingTransaction(surface); } @Override public SurfaceControl.Builder makeAnimationLeash() { return mHost.makeAnimationLeash(); } @Override public SurfaceControl getAnimationLeashParent() { return mHost.getSurfaceControl(); } @Override public SurfaceControl getSurfaceControl() { return mDimLayer; } @Override public SurfaceControl getParentSurfaceControl() { return mHost.getSurfaceControl(); } @Override public int getSurfaceWidth() { // This will determine the size of the leash created. This should be the size of the // host and not the dim layer since the dim layer may get bigger during animation. If // that occurs, the leash size cannot change so we need to ensure the leash is big // enough that the dim layer can grow. // This works because the mHost will be a Task which has the display bounds. return mHost.getSurfaceWidth(); } @Override public int getSurfaceHeight() { // See getSurfaceWidth() above for explanation. return mHost.getSurfaceHeight(); } } private class DimState { SurfaceControl mSurfaceControl; @VisibleForTesting class DimState { /** * The layer where property changes should be invoked on. */ SurfaceControl mDimLayer; boolean mDimming; boolean isVisible; SurfaceAnimator mSurfaceAnimator; /** * Used for Dims not assosciated with a WindowContainer. See {@link Dimmer#dimAbove} for * Used for Dims not associated with a WindowContainer. See {@link Dimmer#dimAbove} for * details on Dim lifecycle. */ boolean mDontReset; DimState(SurfaceControl ctl) { mSurfaceControl = ctl; DimState(SurfaceControl dimLayer) { mDimLayer = dimLayer; mDimming = true; mSurfaceAnimator = new SurfaceAnimator(new DimAnimatable(dimLayer), () -> { if (!mDimming) { mDimLayer.destroy(); } }, mHost.mService.mAnimator::addAfterPrepareSurfacesRunnable, mHost.mService); } } }; private ArrayMap<WindowContainer, DimState> mDimLayerUsers = new ArrayMap<>(); @VisibleForTesting ArrayMap<WindowContainer, DimState> mDimLayerUsers = new ArrayMap<>(); /** * The {@link WindowContainer} that our Dim's are bounded to. We may be dimming on behalf of the Loading @@ -56,19 +137,18 @@ class Dimmer { mHost = host; } SurfaceControl makeDimLayer() { final SurfaceControl control = mHost.makeChildSurface(null) private SurfaceControl makeDimLayer() { return mHost.makeChildSurface(null) .setParent(mHost.getSurfaceControl()) .setColorLayer(true) .setName("Dim Layer for - " + mHost.getName()) .build(); return control; } /** * Retreive the DimState for a given child of the host. */ DimState getDimState(WindowContainer container) { private DimState getDimState(WindowContainer container) { DimState state = mDimLayerUsers.get(container); if (state == null) { final SurfaceControl ctl = makeDimLayer(); Loading @@ -88,14 +168,12 @@ class Dimmer { private void dim(SurfaceControl.Transaction t, WindowContainer container, int relativeLayer, float alpha) { final DimState d = getDimState(container); t.show(d.mSurfaceControl); if (container != null) { t.setRelativeLayer(d.mSurfaceControl, container.getSurfaceControl(), relativeLayer); t.setRelativeLayer(d.mDimLayer, container.getSurfaceControl(), relativeLayer); } else { t.setLayer(d.mSurfaceControl, Integer.MAX_VALUE); t.setLayer(d.mDimLayer, Integer.MAX_VALUE); } t.setAlpha(d.mSurfaceControl, alpha); t.setAlpha(d.mDimLayer, alpha); d.mDimming = true; } Loading @@ -107,9 +185,11 @@ class Dimmer { */ void stopDim(SurfaceControl.Transaction t) { DimState d = getDimState(null); t.hide(d.mSurfaceControl); t.hide(d.mDimLayer); d.isVisible = false; d.mDontReset = false; } /** * Place a Dim above the entire host container. The caller is responsible for calling stopDim to * remove this effect. If the Dim can be assosciated with a particular child of the host Loading Loading @@ -159,7 +239,7 @@ class Dimmer { void resetDimStates() { for (int i = mDimLayerUsers.size() - 1; i >= 0; i--) { final DimState state = mDimLayerUsers.valueAt(i); if (state.mDontReset == false) { if (!state.mDontReset) { state.mDimming = false; } } Loading @@ -177,19 +257,80 @@ class Dimmer { boolean didSomething = false; for (int i = mDimLayerUsers.size() - 1; i >= 0; i--) { DimState state = mDimLayerUsers.valueAt(i); WindowContainer container = mDimLayerUsers.keyAt(i); // TODO: We want to animate the addition and removal of Dim's instead of immediately // acting. When we do this we need to take care to account for the "Replacing Windows" // case (and seamless dim transfer). if (state.mDimming == false) { if (!state.mDimming) { mDimLayerUsers.removeAt(i); state.mSurfaceControl.destroy(); startDimExit(container, state.mSurfaceAnimator, t); } else { didSomething = true; // TODO: Once we use geometry from hierarchy this falls away. t.setSize(state.mSurfaceControl, bounds.width(), bounds.height()); t.setPosition(state.mSurfaceControl, bounds.left, bounds.top); t.setSize(state.mDimLayer, bounds.width(), bounds.height()); t.setPosition(state.mDimLayer, bounds.left, bounds.top); if (!state.isVisible) { state.isVisible = true; t.show(state.mDimLayer); startDimEnter(container, state.mSurfaceAnimator, t); } } } return didSomething; } private void startDimEnter(WindowContainer container, SurfaceAnimator animator, SurfaceControl.Transaction t) { startAnim(container, animator, t, 0 /* startAlpha */, 1 /* endAlpha */); } private void startDimExit(WindowContainer container, SurfaceAnimator animator, SurfaceControl.Transaction t) { startAnim(container, animator, t, 1 /* startAlpha */, 0 /* endAlpha */); } private void startAnim(WindowContainer container, SurfaceAnimator animator, SurfaceControl.Transaction t, float startAlpha, float endAlpha) { animator.startAnimation(t, new LocalAnimationAdapter( new AlphaAnimationSpec(startAlpha, endAlpha, getDimDuration(container)), mHost.mService.mSurfaceAnimationRunner), false /* hidden */); } private long getDimDuration(WindowContainer container) { // If there's no container, then there isn't an animation occurring while dimming. Set the // duration to 0 so it immediately dims to the set alpha. if (container == null) { return 0; } // Otherwise use the same duration as the animation on the WindowContainer AnimationAdapter animationAdapter = container.mSurfaceAnimator.getAnimation(); return animationAdapter == null ? DEFAULT_DIM_ANIM_DURATION : animationAdapter.getDurationHint(); } private static class AlphaAnimationSpec implements LocalAnimationAdapter.AnimationSpec { private final long mDuration; private final float mFromAlpha; private final float mToAlpha; AlphaAnimationSpec(float fromAlpha, float toAlpha, long duration) { mFromAlpha = fromAlpha; mToAlpha = toAlpha; mDuration = duration; } @Override public long getDuration() { return mDuration; } @Override public void apply(SurfaceControl.Transaction t, SurfaceControl sc, long currentPlayTime) { float alpha = ((float) currentPlayTime / getDuration()) * (mToAlpha - mFromAlpha) + mFromAlpha; t.setAlpha(sc, alpha); } } }
services/core/java/com/android/server/wm/DisplayContent.java +18 −0 Original line number Diff line number Diff line Loading @@ -3599,6 +3599,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } private final class AboveAppWindowContainers extends NonAppWindowContainers { private final Dimmer mDimmer = new Dimmer(this); private final Rect mTmpDimBoundsRect = new Rect(); AboveAppWindowContainers(String name, WindowManagerService service) { super(name, service); } Loading Loading @@ -3630,6 +3632,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo imeContainer.assignRelativeLayer(t, getSurfaceControl(), Integer.MAX_VALUE); } } @Override Dimmer getDimmer() { return mDimmer; } @Override void prepareSurfaces() { mDimmer.resetDimStates(); super.prepareSurfaces(); getBounds(mTmpDimBoundsRect); if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) { scheduleAnimation(); } } } /** Loading
services/core/java/com/android/server/wm/Task.java +2 −1 Original line number Diff line number Diff line Loading @@ -462,8 +462,8 @@ class Task extends WindowContainer<AppWindowToken> { } else { mStack.getBounds(mTmpRect); mTmpRect.intersect(getBounds()); } out.set(mTmpRect); } } else { out.set(getBounds()); } Loading Loading @@ -640,6 +640,7 @@ class Task extends WindowContainer<AppWindowToken> { mPreserveNonFloatingState = false; } @Override Dimmer getDimmer() { return mDimmer; } Loading
services/core/java/com/android/server/wm/TaskStack.java +1 −0 Original line number Diff line number Diff line Loading @@ -1722,6 +1722,7 @@ public class TaskStack extends WindowContainer<Task> implements || activityType == ACTIVITY_TYPE_ASSISTANT; } @Override Dimmer getDimmer() { return mDimmer; } Loading
services/core/java/com/android/server/wm/WindowContainer.java +7 −0 Original line number Diff line number Diff line Loading @@ -1231,4 +1231,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< outPos.offset(-parentBounds.left, -parentBounds.top); } } Dimmer getDimmer() { if (mParent == null) { return null; } return mParent.getDimmer(); } }