summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Marzia Favaro <marziana@google.com> 2023-11-03 17:32:18 +0000
committer Marzia Favaro <marziana@google.com> 2023-11-27 16:59:00 +0000
commit5496dfa0eb103f7954df94aea257ce482bde184d (patch)
treea30f5f85beecb94cf0204911cef196b3bddec314
parenta62c4d69b5d99618d356bccd8717863f578da94b (diff)
Improve readability and add protections against use after release NPE
Preventively ensure the dimLayer has not been released before trying to access it. Fix: 308448047 Test: atest CtsWindowManagerDeviceOther:android.server.wm.other.MinimalPostProcessingTests#testTwoVisibleWindowsSecondOnePrefersMinimalPostProcessing --iteration 100 Test: atest DimmerTests Change-Id: Id08838e0a98ba949382442b8fac8e81156d1aa40
-rw-r--r--data/etc/services.core.protolog.json42
-rw-r--r--services/core/java/com/android/server/wm/Dimmer.java4
-rw-r--r--services/core/java/com/android/server/wm/DimmerAnimationHelper.java334
-rw-r--r--services/core/java/com/android/server/wm/SmoothDimmer.java423
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DimmerTests.java3
5 files changed, 475 insertions, 331 deletions
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index dc2b0561957d..9d76c9f5fc93 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -535,6 +535,12 @@
"group": "WM_DEBUG_TASKS",
"at": "com\/android\/server\/wm\/ActivityStarter.java"
},
+ "-1582845629": {
+ "message": "Starting animation on %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_DIMMER",
+ "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java"
+ },
"-1575977269": {
"message": "Skipping %s: mismatch root %s",
"level": "DEBUG",
@@ -925,6 +931,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "-1243510456": {
+ "message": "Dim animation requested: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_DIMMER",
+ "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java"
+ },
"-1237827119": {
"message": "Schedule remove starting %s startingWindow=%s animate=%b Callers=%s",
"level": "VERBOSE",
@@ -1177,6 +1189,12 @@
"group": "WM_DEBUG_BACK_PREVIEW",
"at": "com\/android\/server\/wm\/BackNavigationController.java"
},
+ "-1028213464": {
+ "message": "%s skipping animation and directly setting alpha=%f, blur=%d",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_DIMMER",
+ "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java"
+ },
"-1022146708": {
"message": "Skipping %s: mismatch activity type",
"level": "DEBUG",
@@ -1807,12 +1825,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-504637678": {
- "message": "Starting animation on dim layer %s, requested by %s, alpha: %f -> %f, blur: %d -> %d",
- "level": "VERBOSE",
- "group": "WM_DEBUG_DIMMER",
- "at": "com\/android\/server\/wm\/SmoothDimmer.java"
- },
"-503656156": {
"message": "Update process config of %s to new config %s",
"level": "VERBOSE",
@@ -2731,12 +2743,6 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
- "309039362": {
- "message": "SURFACE MATRIX [%f,%f,%f,%f]: %s",
- "level": "INFO",
- "group": "WM_SHOW_TRANSACTIONS",
- "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
- },
"312030608": {
"message": "New topFocusedDisplayId=%d",
"level": "DEBUG",
@@ -3091,12 +3097,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "633654009": {
- "message": "SURFACE POS (setPositionInTransaction) @ (%f,%f): %s",
- "level": "INFO",
- "group": "WM_SHOW_TRANSACTIONS",
- "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
- },
"638429464": {
"message": "\tRemove container=%s",
"level": "DEBUG",
@@ -4039,12 +4039,6 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
- "1620751818": {
- "message": "Dim %s skipping animation and directly setting alpha=%f, blur=%d",
- "level": "DEBUG",
- "group": "WM_DEBUG_DIMMER",
- "at": "com\/android\/server\/wm\/SmoothDimmer.java"
- },
"1621562070": {
"message": " startWCT=%s",
"level": "VERBOSE",
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 2fabb0ea686a..7ce9de4e1c24 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -83,6 +83,7 @@ public abstract class Dimmer {
/**
* Mark all dims as pending completion on the next call to {@link #updateDims}
*
+ * Called before iterating on mHost's children, first step of dimming.
* This is intended for us by the host container, to be called at the beginning of
* {@link WindowContainer#prepareSurfaces}. After calling this, the container should
* chain {@link WindowContainer#prepareSurfaces} down to it's children to give them
@@ -100,8 +101,7 @@ public abstract class Dimmer {
/**
* Call after invoking {@link WindowContainer#prepareSurfaces} on children as
- * described in {@link #resetDimStates}. The dim bounds returned by {@link #resetDimStates}
- * should be set before calling this method.
+ * described in {@link #resetDimStates}.
*
* @param t A transaction in which to update the dims.
* @return true if any Dims were updated.
diff --git a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
new file mode 100644
index 000000000000..e91857f1da82
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2023 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.server.wm;
+
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_DIMMER;
+import static com.android.server.wm.AlphaAnimationSpecProto.DURATION_MS;
+import static com.android.server.wm.AlphaAnimationSpecProto.FROM;
+import static com.android.server.wm.AlphaAnimationSpecProto.TO;
+import static com.android.server.wm.AnimationSpecProto.ALPHA;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_DIMMER;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.util.Log;
+import android.util.proto.ProtoOutputStream;
+import android.view.SurfaceControl;
+
+import com.android.internal.protolog.common.ProtoLog;
+
+import java.io.PrintWriter;
+
+/**
+ * Contains the information relative to the changes to apply to the dim layer
+ */
+public class DimmerAnimationHelper {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "DimmerAnimationHelper" : TAG_WM;
+ private static final int DEFAULT_DIM_ANIM_DURATION_MS = 200;
+
+ /**
+ * Contains the requested changes
+ */
+ static class Change {
+ private float mAlpha = -1f;
+ private int mBlurRadius = -1;
+ private WindowContainer mDimmingContainer = null;
+ private int mRelativeLayer = -1;
+ private static final float EPSILON = 0.0001f;
+
+ Change() {}
+
+ Change(Change other) {
+ mAlpha = other.mAlpha;
+ mBlurRadius = other.mBlurRadius;
+ mDimmingContainer = other.mDimmingContainer;
+ mRelativeLayer = other.mRelativeLayer;
+ }
+
+ // Same alpha and blur
+ boolean hasSameVisualProperties(Change other) {
+ return Math.abs(mAlpha - other.mAlpha) < EPSILON && mBlurRadius == other.mBlurRadius;
+ }
+
+ boolean hasSameDimmingContainer(Change other) {
+ return mDimmingContainer != null && mDimmingContainer == other.mDimmingContainer;
+ }
+
+ void inheritPropertiesFromAnimation(AnimationSpec anim) {
+ mAlpha = anim.mCurrentAlpha;
+ mBlurRadius = anim.mCurrentBlur;
+ }
+
+ @Override
+ public String toString() {
+ return "Dim state: alpha=" + mAlpha + ", blur=" + mBlurRadius + ", container="
+ + mDimmingContainer + ", relativePosition=" + mRelativeLayer;
+ }
+ }
+
+ private Change mCurrentProperties = new Change();
+ private Change mRequestedProperties = new Change();
+ private AnimationSpec mAlphaAnimationSpec;
+
+ private final AnimationAdapterFactory mAnimationAdapterFactory;
+ private AnimationAdapter mLocalAnimationAdapter;
+
+ DimmerAnimationHelper(AnimationAdapterFactory animationFactory) {
+ mAnimationAdapterFactory = animationFactory;
+ }
+
+ void setExitParameters() {
+ setRequestedRelativeParent(mRequestedProperties.mDimmingContainer, -1 /* relativeLayer */);
+ setRequestedAppearance(0f /* alpha */, 0 /* blur */);
+ }
+
+ // Sets a requested change without applying it immediately
+ void setRequestedRelativeParent(WindowContainer relativeParent, int relativeLayer) {
+ mRequestedProperties.mDimmingContainer = relativeParent;
+ mRequestedProperties.mRelativeLayer = relativeLayer;
+ }
+
+ // Sets a requested change without applying it immediately
+ void setRequestedAppearance(float alpha, int blurRadius) {
+ mRequestedProperties.mAlpha = alpha;
+ mRequestedProperties.mBlurRadius = blurRadius;
+ }
+
+ /**
+ * Commit the last changes we received. Called after
+ * {@link Change#setExitParameters()},
+ * {@link Change#setRequestedRelativeParent(WindowContainer, int)}, or
+ * {@link Change#setRequestedAppearance(float, int)}
+ */
+ void applyChanges(SurfaceControl.Transaction t, SmoothDimmer.DimState dim) {
+ if (mRequestedProperties.mDimmingContainer == null) {
+ Log.e(TAG, this + " does not have a dimming container. Have you forgotten to "
+ + "call adjustRelativeLayer?");
+ return;
+ }
+ if (mRequestedProperties.mDimmingContainer.mSurfaceControl == null) {
+ Log.w(TAG, "container " + mRequestedProperties.mDimmingContainer
+ + "does not have a surface");
+ dim.remove(t);
+ return;
+ }
+
+ dim.ensureVisible(t);
+ relativeReparent(dim.mDimSurface,
+ mRequestedProperties.mDimmingContainer.getSurfaceControl(),
+ mRequestedProperties.mRelativeLayer, t);
+
+ if (!mCurrentProperties.hasSameVisualProperties(mRequestedProperties)) {
+ stopCurrentAnimation(dim.mDimSurface);
+
+ if (dim.mSkipAnimation
+ // If the container doesn't change but requests a dim change, then it is
+ // directly providing us the animated values
+ || (mRequestedProperties.hasSameDimmingContainer(mCurrentProperties)
+ && dim.isDimming())) {
+ ProtoLog.d(WM_DEBUG_DIMMER,
+ "%s skipping animation and directly setting alpha=%f, blur=%d",
+ dim, mRequestedProperties.mAlpha,
+ mRequestedProperties.mBlurRadius);
+ setAlphaBlur(dim.mDimSurface, mRequestedProperties.mAlpha,
+ mRequestedProperties.mBlurRadius, t);
+ dim.mSkipAnimation = false;
+ } else {
+ startAnimation(t, dim);
+ }
+
+ } else if (!dim.isDimming()) {
+ // We are not dimming, so we tried the exit animation but the alpha is already 0,
+ // therefore, let's just remove this surface
+ dim.remove(t);
+ }
+ mCurrentProperties = new Change(mRequestedProperties);
+ }
+
+ private void startAnimation(
+ SurfaceControl.Transaction t, SmoothDimmer.DimState dim) {
+ ProtoLog.v(WM_DEBUG_DIMMER, "Starting animation on %s", dim);
+ mAlphaAnimationSpec = getRequestedAnimationSpec();
+ mLocalAnimationAdapter = mAnimationAdapterFactory.get(mAlphaAnimationSpec,
+ dim.mHostContainer.mWmService.mSurfaceAnimationRunner);
+
+ float targetAlpha = mRequestedProperties.mAlpha;
+ int targetBlur = mRequestedProperties.mBlurRadius;
+
+ mLocalAnimationAdapter.startAnimation(dim.mDimSurface, t,
+ ANIMATION_TYPE_DIMMER, /* finishCallback */ (type, animator) -> {
+ setAlphaBlur(dim.mDimSurface, targetAlpha, targetBlur, t);
+ if (targetAlpha == 0f && !dim.isDimming()) {
+ dim.remove(t);
+ }
+ mLocalAnimationAdapter = null;
+ mAlphaAnimationSpec = null;
+ });
+ }
+
+ private boolean isAnimating() {
+ return mAlphaAnimationSpec != null;
+ }
+
+ void stopCurrentAnimation(SurfaceControl surface) {
+ if (mLocalAnimationAdapter != null && isAnimating()) {
+ // Save the current animation progress and cancel the animation
+ mCurrentProperties.inheritPropertiesFromAnimation(mAlphaAnimationSpec);
+ mLocalAnimationAdapter.onAnimationCancelled(surface);
+ mLocalAnimationAdapter = null;
+ mAlphaAnimationSpec = null;
+ }
+ }
+
+ private AnimationSpec getRequestedAnimationSpec() {
+ final float startAlpha = Math.max(mCurrentProperties.mAlpha, 0f);
+ final int startBlur = Math.max(mCurrentProperties.mBlurRadius, 0);
+ long duration = (long) (getDimDuration(mRequestedProperties.mDimmingContainer)
+ * Math.abs(mRequestedProperties.mAlpha - startAlpha));
+
+ final AnimationSpec spec = new AnimationSpec(
+ new AnimationSpec.AnimationExtremes<>(startAlpha, mRequestedProperties.mAlpha),
+ new AnimationSpec.AnimationExtremes<>(startBlur, mRequestedProperties.mBlurRadius),
+ duration
+ );
+ ProtoLog.v(WM_DEBUG_DIMMER, "Dim animation requested: %s", spec);
+ return spec;
+ }
+
+ /**
+ * Change the relative parent of this dim layer
+ */
+ void relativeReparent(SurfaceControl dimLayer, SurfaceControl relativeParent,
+ int relativePosition, SurfaceControl.Transaction t) {
+ try {
+ t.setRelativeLayer(dimLayer, relativeParent, relativePosition);
+ } catch (NullPointerException e) {
+ Log.w(TAG, "Tried to change parent of dim " + dimLayer + " after remove", e);
+ }
+ }
+
+ void setAlphaBlur(SurfaceControl sc, float alpha, int blur, SurfaceControl.Transaction t) {
+ try {
+ t.setAlpha(sc, alpha);
+ t.setBackgroundBlurRadius(sc, blur);
+ } catch (NullPointerException e) {
+ Log.w(TAG , "Tried to change look of dim " + sc + " after remove", e);
+ }
+ }
+
+ private long getDimDuration(WindowContainer container) {
+ // Use the same duration as the animation on the WindowContainer
+ AnimationAdapter animationAdapter = container.mSurfaceAnimator.getAnimation();
+ final float durationScale = container.mWmService.getTransitionAnimationScaleLocked();
+ return animationAdapter == null ? (long) (DEFAULT_DIM_ANIM_DURATION_MS * durationScale)
+ : animationAdapter.getDurationHint();
+ }
+
+ /**
+ * Collects the animation specifics
+ */
+ static class AnimationSpec implements LocalAnimationAdapter.AnimationSpec {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "DimmerAnimationSpec" : TAG_WM;
+
+ static class AnimationExtremes<T> {
+ final T mStartValue;
+ final T mFinishValue;
+
+ AnimationExtremes(T fromValue, T toValue) {
+ mStartValue = fromValue;
+ mFinishValue = toValue;
+ }
+
+ @Override
+ public String toString() {
+ return "[" + mStartValue + "->" + mFinishValue + "]";
+ }
+ }
+
+ private final long mDuration;
+ private final AnimationSpec.AnimationExtremes<Float> mAlpha;
+ private final AnimationSpec.AnimationExtremes<Integer> mBlur;
+
+ float mCurrentAlpha = 0;
+ int mCurrentBlur = 0;
+ boolean mStarted = false;
+
+ AnimationSpec(AnimationSpec.AnimationExtremes<Float> alpha,
+ AnimationSpec.AnimationExtremes<Integer> blur, long duration) {
+ mAlpha = alpha;
+ mBlur = blur;
+ mDuration = duration;
+ }
+
+ @Override
+ public long getDuration() {
+ return mDuration;
+ }
+
+ @Override
+ public void apply(SurfaceControl.Transaction t, SurfaceControl sc, long currentPlayTime) {
+ if (!mStarted) {
+ // The first frame would end up in the sync transaction, and since this could be
+ // applied after the animation transaction, we avoid putting visible changes here.
+ // The initial state of the animation matches the current state of the dim anyway.
+ mStarted = true;
+ return;
+ }
+ final float fraction = getFraction(currentPlayTime);
+ mCurrentAlpha =
+ fraction * (mAlpha.mFinishValue - mAlpha.mStartValue) + mAlpha.mStartValue;
+ mCurrentBlur =
+ (int) fraction * (mBlur.mFinishValue - mBlur.mStartValue) + mBlur.mStartValue;
+ if (sc.isValid()) {
+ t.setAlpha(sc, mCurrentAlpha);
+ t.setBackgroundBlurRadius(sc, mCurrentBlur);
+ } else {
+ Log.w(TAG, "Dimmer#AnimationSpec tried to access " + sc + " after release");
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Animation spec: alpha=" + mAlpha + ", blur=" + mBlur;
+ }
+
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix); pw.print("from_alpha="); pw.print(mAlpha.mStartValue);
+ pw.print(" to_alpha="); pw.print(mAlpha.mFinishValue);
+ pw.print(prefix); pw.print("from_blur="); pw.print(mBlur.mStartValue);
+ pw.print(" to_blur="); pw.print(mBlur.mFinishValue);
+ pw.print(" duration="); pw.println(mDuration);
+ }
+
+ @Override
+ public void dumpDebugInner(ProtoOutputStream proto) {
+ final long token = proto.start(ALPHA);
+ proto.write(FROM, mAlpha.mStartValue);
+ proto.write(TO, mAlpha.mFinishValue);
+ proto.write(DURATION_MS, mDuration);
+ proto.end(token);
+ }
+ }
+
+ static class AnimationAdapterFactory {
+ public AnimationAdapter get(LocalAnimationAdapter.AnimationSpec alphaAnimationSpec,
+ SurfaceAnimationRunner runner) {
+ return new LocalAnimationAdapter(alphaAnimationSpec, runner);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/SmoothDimmer.java b/services/core/java/com/android/server/wm/SmoothDimmer.java
index 2549bbf70e9f..b5d94a2efbdf 100644
--- a/services/core/java/com/android/server/wm/SmoothDimmer.java
+++ b/services/core/java/com/android/server/wm/SmoothDimmer.java
@@ -17,397 +17,212 @@
package com.android.server.wm;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_DIMMER;
-import static com.android.server.wm.AlphaAnimationSpecProto.DURATION_MS;
-import static com.android.server.wm.AlphaAnimationSpecProto.FROM;
-import static com.android.server.wm.AlphaAnimationSpecProto.TO;
-import static com.android.server.wm.AnimationSpecProto.ALPHA;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_DIMMER;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.graphics.Rect;
import android.util.Log;
-import android.util.proto.ProtoOutputStream;
import android.view.Surface;
import android.view.SurfaceControl;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
-import java.io.PrintWriter;
-
class SmoothDimmer extends Dimmer {
+
private static final String TAG = TAG_WITH_CLASS_NAME ? "Dimmer" : TAG_WM;
- private static final float EPSILON = 0.0001f;
- // This is in milliseconds.
- private static final int DEFAULT_DIM_ANIM_DURATION = 200;
DimState mDimState;
- private WindowContainer mLastRequestedDimContainer;
- private final AnimationAdapterFactory mAnimationAdapterFactory;
+ final DimmerAnimationHelper.AnimationAdapterFactory mAnimationAdapterFactory;
+ /**
+ * Controls the dim behaviour
+ */
@VisibleForTesting
class DimState {
- /**
- * The layer where property changes should be invoked on.
- */
- SurfaceControl mDimLayer;
- boolean mDimming;
- boolean mIsVisible;
-
+ /** Related objects */
+ SurfaceControl mDimSurface;
+ final WindowContainer mHostContainer;
+ // The last container to request to dim
+ private WindowContainer mLastRequestedDimContainer;
+ /** Animation */
+ private final DimmerAnimationHelper mAnimationHelper;
+ boolean mSkipAnimation = false;
+ // Determines whether the dim layer should animate before destroying.
+ boolean mAnimateExit = true;
+ /** Surface visibility and bounds */
+ private boolean mIsVisible = false;
// TODO(b/64816140): Remove after confirming dimmer layer always matches its container.
final Rect mDimBounds = new Rect();
- /**
- * Determines whether the dim layer should animate before destroying.
- */
- boolean mAnimateExit = true;
-
- /**
- * Used for Dims not associated with a WindowContainer.
- * See {@link Dimmer#adjustRelativeLayer(WindowContainer, int)} for details on Dim
- * lifecycle.
- */
- boolean mDontReset;
-
- Change mCurrentProperties;
- Change mRequestedProperties;
- private AnimationSpec mAlphaAnimationSpec;
- private AnimationAdapter mLocalAnimationAdapter;
-
- static class Change {
- private float mAlpha = -1f;
- private int mBlurRadius = -1;
- private WindowContainer mDimmingContainer = null;
- private int mRelativeLayer = -1;
- private boolean mSkipAnimation = false;
-
- Change() {}
-
- Change(Change other) {
- mAlpha = other.mAlpha;
- mBlurRadius = other.mBlurRadius;
- mDimmingContainer = other.mDimmingContainer;
- mRelativeLayer = other.mRelativeLayer;
- }
-
- @Override
- public String toString() {
- return "Dim state: alpha=" + mAlpha + ", blur=" + mBlurRadius + ", container="
- + mDimmingContainer + ", relativePosition=" + mRelativeLayer
- + ", skipAnimation=" + mSkipAnimation;
+ DimState() {
+ mHostContainer = mHost;
+ mAnimationHelper = new DimmerAnimationHelper(mAnimationAdapterFactory);
+ try {
+ mDimSurface = makeDimLayer();
+ } catch (Surface.OutOfResourcesException e) {
+ Log.w(TAG, "OutOfResourcesException creating dim surface");
}
}
- DimState(SurfaceControl dimLayer) {
- mDimLayer = dimLayer;
- mDimming = true;
- mCurrentProperties = new Change();
- mRequestedProperties = new Change();
- }
-
- void setExitParameters(WindowContainer container) {
- setRequestedRelativeParent(container, -1 /* relativeLayer */);
- setRequestedAppearance(0f /* alpha */, 0 /* blur */);
+ void ensureVisible(SurfaceControl.Transaction t) {
+ if (!mIsVisible) {
+ t.show(mDimSurface);
+ t.setAlpha(mDimSurface, 0f);
+ mIsVisible = true;
+ }
}
- // Sets a requested change without applying it immediately
- void setRequestedRelativeParent(WindowContainer relativeParent, int relativeLayer) {
- mRequestedProperties.mDimmingContainer = relativeParent;
- mRequestedProperties.mRelativeLayer = relativeLayer;
+ void adjustSurfaceLayout(SurfaceControl.Transaction t) {
+ // TODO: Once we use geometry from hierarchy this falls away.
+ t.setPosition(mDimSurface, mDimBounds.left, mDimBounds.top);
+ t.setWindowCrop(mDimSurface, mDimBounds.width(), mDimBounds.height());
}
- // Sets a requested change without applying it immediately
- void setRequestedAppearance(float alpha, int blurRadius) {
- mRequestedProperties.mAlpha = alpha;
- mRequestedProperties.mBlurRadius = blurRadius;
+ /**
+ * Set the parameters to prepare the dim to change its appearance
+ */
+ void prepareLookChange(float alpha, int blurRadius) {
+ mAnimationHelper.setRequestedAppearance(alpha, blurRadius);
}
/**
- * Commit the last changes we received. Called after
- * {@link Change#setExitParameters(WindowContainer)},
- * {@link Change#setRequestedRelativeParent(WindowContainer, int)}, or
- * {@link Change#setRequestedAppearance(float, int)}
+ * Prepare the dim for the exit animation
*/
- void applyChanges(SurfaceControl.Transaction t) {
- if (mRequestedProperties.mDimmingContainer == null) {
- Log.e(TAG, this + " does not have a dimming container. Have you forgotten to "
- + "call adjustRelativeLayer?");
- return;
- }
- if (mRequestedProperties.mDimmingContainer.mSurfaceControl == null) {
- Log.w(TAG, "container " + mRequestedProperties.mDimmingContainer
- + "does not have a surface");
- return;
- }
- if (!mDimState.mIsVisible) {
- mDimState.mIsVisible = true;
- t.show(mDimState.mDimLayer);
+ void exit(SurfaceControl.Transaction t) {
+ if (!mAnimateExit) {
+ remove(t);
+ } else {
+ mAnimationHelper.setExitParameters();
+ setReady(t);
}
- t.setRelativeLayer(mDimLayer,
- mRequestedProperties.mDimmingContainer.getSurfaceControl(),
- mRequestedProperties.mRelativeLayer);
+ }
- if (aspectChanged()) {
- if (isAnimating()) {
- mLocalAnimationAdapter.onAnimationCancelled(mDimLayer);
- }
- if (mRequestedProperties.mSkipAnimation
- || (!dimmingContainerChanged() && mDimming)) {
- // If the dimming container has not changed, then it is running its own
- // animation, thus we can directly set the values we get requested, unless it's
- // the exiting animation
- ProtoLog.d(WM_DEBUG_DIMMER,
- "Dim %s skipping animation and directly setting alpha=%f, blur=%d",
- mDimLayer, mRequestedProperties.mAlpha,
- mRequestedProperties.mBlurRadius);
- t.setAlpha(mDimLayer, mRequestedProperties.mAlpha);
- t.setBackgroundBlurRadius(mDimLayer, mRequestedProperties.mBlurRadius);
- mRequestedProperties.mSkipAnimation = false;
- } else {
- startAnimation(t);
- }
+ void remove(SurfaceControl.Transaction t) {
+ mAnimationHelper.stopCurrentAnimation(mDimSurface);
+ if (mDimSurface.isValid()) {
+ t.remove(mDimSurface);
+ ProtoLog.d(WM_DEBUG_DIMMER,
+ "Removing dim surface %s on transaction %s", this, t);
+ } else {
+ Log.w(TAG, "Tried to remove " + mDimSurface + " multiple times\n");
}
- mCurrentProperties = new Change(mRequestedProperties);
}
- private void startAnimation(SurfaceControl.Transaction t) {
- mAlphaAnimationSpec = getRequestedAnimationSpec(mRequestedProperties.mAlpha,
- mRequestedProperties.mBlurRadius);
- mLocalAnimationAdapter = mAnimationAdapterFactory.get(mAlphaAnimationSpec,
- mHost.mWmService.mSurfaceAnimationRunner);
-
- mLocalAnimationAdapter.startAnimation(mDimLayer, t,
- ANIMATION_TYPE_DIMMER, (type, animator) -> {
- t.setAlpha(mDimLayer, mRequestedProperties.mAlpha);
- t.setBackgroundBlurRadius(mDimLayer, mRequestedProperties.mBlurRadius);
- if (mRequestedProperties.mAlpha == 0f && !mDimming) {
- ProtoLog.d(WM_DEBUG_DIMMER,
- "Removing dim surface %s on transaction %s", mDimLayer, t);
- t.remove(mDimLayer);
- }
- mLocalAnimationAdapter = null;
- mAlphaAnimationSpec = null;
- });
+ @Override
+ public String toString() {
+ return "SmoothDimmer#DimState with host=" + mHostContainer + ", surface=" + mDimSurface;
}
- private boolean isAnimating() {
- return mAlphaAnimationSpec != null;
+ /**
+ * Set the parameters to prepare the dim to be relative parented to the dimming container
+ */
+ void prepareReparent(WindowContainer relativeParent, int relativeLayer) {
+ mAnimationHelper.setRequestedRelativeParent(relativeParent, relativeLayer);
}
- private boolean aspectChanged() {
- return Math.abs(mRequestedProperties.mAlpha - mCurrentProperties.mAlpha) > EPSILON
- || mRequestedProperties.mBlurRadius != mCurrentProperties.mBlurRadius;
+ /**
+ * Call when all the changes have been requested to have them applied
+ * @param t The transaction in which to apply the changes
+ */
+ void setReady(SurfaceControl.Transaction t) {
+ mAnimationHelper.applyChanges(t, this);
}
- private boolean dimmingContainerChanged() {
- return mRequestedProperties.mDimmingContainer != mCurrentProperties.mDimmingContainer;
+ /**
+ * Whether anyone is currently requesting the dim
+ */
+ boolean isDimming() {
+ return mLastRequestedDimContainer != null;
}
- private AnimationSpec getRequestedAnimationSpec(float targetAlpha, int targetBlur) {
- final float startAlpha;
- final int startBlur;
- if (mAlphaAnimationSpec != null) {
- startAlpha = mAlphaAnimationSpec.mCurrentAlpha;
- startBlur = mAlphaAnimationSpec.mCurrentBlur;
- } else {
- startAlpha = Math.max(mCurrentProperties.mAlpha, 0f);
- startBlur = Math.max(mCurrentProperties.mBlurRadius, 0);
- }
- long duration = (long) (getDimDuration(mRequestedProperties.mDimmingContainer)
- * Math.abs(targetAlpha - startAlpha));
-
- ProtoLog.v(WM_DEBUG_DIMMER, "Starting animation on dim layer %s, requested by %s, "
- + "alpha: %f -> %f, blur: %d -> %d",
- mDimLayer, mRequestedProperties.mDimmingContainer, startAlpha, targetAlpha,
- startBlur, targetBlur);
- return new AnimationSpec(
- new AnimationExtremes<>(startAlpha, targetAlpha),
- new AnimationExtremes<>(startBlur, targetBlur),
- duration
- );
+ private SurfaceControl makeDimLayer() {
+ return mHost.makeChildSurface(null)
+ .setParent(mHost.getSurfaceControl())
+ .setColorLayer()
+ .setName("Dim Layer for - " + mHost.getName())
+ .setCallsite("DimLayer.makeDimLayer")
+ .build();
}
}
protected SmoothDimmer(WindowContainer host) {
- this(host, new AnimationAdapterFactory());
+ this(host, new DimmerAnimationHelper.AnimationAdapterFactory());
}
@VisibleForTesting
- SmoothDimmer(WindowContainer host, AnimationAdapterFactory animationFactory) {
+ SmoothDimmer(WindowContainer host,
+ DimmerAnimationHelper.AnimationAdapterFactory animationFactory) {
super(host);
mAnimationAdapterFactory = animationFactory;
}
- private DimState obtainDimState(WindowContainer container) {
- if (mDimState == null) {
- try {
- final SurfaceControl ctl = makeDimLayer();
- mDimState = new DimState(ctl);
- } catch (Surface.OutOfResourcesException e) {
- Log.w(TAG, "OutOfResourcesException creating dim surface");
- }
- }
-
- mLastRequestedDimContainer = container;
- return mDimState;
- }
-
- private SurfaceControl makeDimLayer() {
- return mHost.makeChildSurface(null)
- .setParent(mHost.getSurfaceControl())
- .setColorLayer()
- .setName("Dim Layer for - " + mHost.getName())
- .setCallsite("Dimmer.makeDimLayer")
- .build();
- }
-
- @Override
- SurfaceControl getDimLayer() {
- return mDimState != null ? mDimState.mDimLayer : null;
- }
-
@Override
void resetDimStates() {
- if (mDimState == null) {
- return;
- }
- if (!mDimState.mDontReset) {
- mDimState.mDimming = false;
- }
- }
-
- @Override
- Rect getDimBounds() {
- return mDimState != null ? mDimState.mDimBounds : null;
- }
-
- @Override
- void dontAnimateExit() {
if (mDimState != null) {
- mDimState.mAnimateExit = false;
+ mDimState.mLastRequestedDimContainer = null;
}
}
@Override
protected void adjustAppearance(WindowContainer container, float alpha, int blurRadius) {
final DimState d = obtainDimState(container);
- mDimState.setRequestedAppearance(alpha, blurRadius);
- d.mDimming = true;
+ d.prepareLookChange(alpha, blurRadius);
}
@Override
protected void adjustRelativeLayer(WindowContainer container, int relativeLayer) {
if (mDimState != null) {
- mDimState.setRequestedRelativeParent(container, relativeLayer);
+ mDimState.prepareReparent(container, relativeLayer);
}
}
+ @Override
boolean updateDims(SurfaceControl.Transaction t) {
if (mDimState == null) {
return false;
}
-
- if (!mDimState.mDimming) {
- // No one is dimming anymore, fade out dim and remove
- if (!mDimState.mAnimateExit) {
- if (mDimState.mDimLayer.isValid()) {
- t.remove(mDimState.mDimLayer);
- }
- } else {
- mDimState.setExitParameters(
- mDimState.mRequestedProperties.mDimmingContainer);
- mDimState.applyChanges(t);
- }
+ if (!mDimState.isDimming()) {
+ // No one is dimming, fade out and remove the dim
+ mDimState.exit(t);
mDimState = null;
return false;
+ } else {
+ // Someone is dimming, show the requested changes
+ mDimState.adjustSurfaceLayout(t);
+ final WindowState ws = mDimState.mLastRequestedDimContainer.asWindowState();
+ if (!mDimState.mIsVisible && ws != null && ws.mActivityRecord != null
+ && ws.mActivityRecord.mStartingData != null) {
+ // Skip enter animation while starting window is on top of its activity
+ mDimState.mSkipAnimation = true;
+ }
+ mDimState.setReady(t);
+ return true;
}
- final Rect bounds = mDimState.mDimBounds;
- // TODO: Once we use geometry from hierarchy this falls away.
- t.setPosition(mDimState.mDimLayer, bounds.left, bounds.top);
- t.setWindowCrop(mDimState.mDimLayer, bounds.width(), bounds.height());
- // Skip enter animation while starting window is on top of its activity
- final WindowState ws = mLastRequestedDimContainer.asWindowState();
- if (!mDimState.mIsVisible && ws != null && ws.mActivityRecord != null
- && ws.mActivityRecord.mStartingData != null) {
- mDimState.mRequestedProperties.mSkipAnimation = true;
- }
- mDimState.applyChanges(t);
- return true;
- }
-
- private long getDimDuration(WindowContainer container) {
- // Use the same duration as the animation on the WindowContainer
- AnimationAdapter animationAdapter = container.mSurfaceAnimator.getAnimation();
- final float durationScale = container.mWmService.getTransitionAnimationScaleLocked();
- return animationAdapter == null ? (long) (DEFAULT_DIM_ANIM_DURATION * durationScale)
- : animationAdapter.getDurationHint();
}
- private static class AnimationExtremes<T> {
- final T mStartValue;
- final T mFinishValue;
-
- AnimationExtremes(T fromValue, T toValue) {
- mStartValue = fromValue;
- mFinishValue = toValue;
+ private DimState obtainDimState(WindowContainer container) {
+ if (mDimState == null) {
+ mDimState = new DimState();
}
+ mDimState.mLastRequestedDimContainer = container;
+ return mDimState;
}
- private static class AnimationSpec implements LocalAnimationAdapter.AnimationSpec {
- private final long mDuration;
- private final AnimationExtremes<Float> mAlpha;
- private final AnimationExtremes<Integer> mBlur;
-
- float mCurrentAlpha = 0;
- int mCurrentBlur = 0;
-
- AnimationSpec(AnimationExtremes<Float> alpha,
- AnimationExtremes<Integer> blur, long duration) {
- mAlpha = alpha;
- mBlur = blur;
- mDuration = duration;
- }
-
- @Override
- public long getDuration() {
- return mDuration;
- }
-
- @Override
- public void apply(SurfaceControl.Transaction t, SurfaceControl sc, long currentPlayTime) {
- final float fraction = getFraction(currentPlayTime);
- mCurrentAlpha =
- fraction * (mAlpha.mFinishValue - mAlpha.mStartValue) + mAlpha.mStartValue;
- mCurrentBlur =
- (int) fraction * (mBlur.mFinishValue - mBlur.mStartValue) + mBlur.mStartValue;
- t.setAlpha(sc, mCurrentAlpha);
- t.setBackgroundBlurRadius(sc, mCurrentBlur);
- }
-
- @Override
- public void dump(PrintWriter pw, String prefix) {
- pw.print(prefix); pw.print("from_alpha="); pw.print(mAlpha.mStartValue);
- pw.print(" to_alpha="); pw.print(mAlpha.mFinishValue);
- pw.print(prefix); pw.print("from_blur="); pw.print(mBlur.mStartValue);
- pw.print(" to_blur="); pw.print(mBlur.mFinishValue);
- pw.print(" duration="); pw.println(mDuration);
- }
-
- @Override
- public void dumpDebugInner(ProtoOutputStream proto) {
- final long token = proto.start(ALPHA);
- proto.write(FROM, mAlpha.mStartValue);
- proto.write(TO, mAlpha.mFinishValue);
- proto.write(DURATION_MS, mDuration);
- proto.end(token);
- }
+ @Override
+ @VisibleForTesting
+ SurfaceControl getDimLayer() {
+ return mDimState != null ? mDimState.mDimSurface : null;
}
- static class AnimationAdapterFactory {
+ @Override
+ Rect getDimBounds() {
+ return mDimState != null ? mDimState.mDimBounds : null;
+ }
- public AnimationAdapter get(LocalAnimationAdapter.AnimationSpec alphaAnimationSpec,
- SurfaceAnimationRunner runner) {
- return new LocalAnimationAdapter(alphaAnimationSpec, runner);
+ @Override
+ void dontAnimateExit() {
+ if (mDimState != null) {
+ mDimState.mAnimateExit = false;
}
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index 9f584911aed7..a831f6a382ed 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -122,7 +122,8 @@ public class DimmerTests extends WindowTestsBase {
}
}
- static class MockAnimationAdapterFactory extends SmoothDimmer.AnimationAdapterFactory {
+ static class MockAnimationAdapterFactory extends DimmerAnimationHelper.AnimationAdapterFactory {
+ @Override
public AnimationAdapter get(LocalAnimationAdapter.AnimationSpec alphaAnimationSpec,
SurfaceAnimationRunner runner) {
return sTestAnimation;