Break pipeline re-entrant call due to dismiss anim
Fixes: 224606120
Test: manual
1. Have one clearable notification in the shade
2. Tap "Clear All"
3. Receive an update to the notification before the animation has
completed
4. Verify no crash
Change-Id: Iefd021ac6bf6ca9c959a6f410ca96f51e77142cd
This commit is contained in:
@@ -46,6 +46,8 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
|
|||||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||||
import com.android.wm.shell.animation.FlingAnimationUtils;
|
import com.android.wm.shell.animation.FlingAnimationUtils;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class SwipeHelper implements Gefingerpoken {
|
public class SwipeHelper implements Gefingerpoken {
|
||||||
static final String TAG = "com.android.systemui.SwipeHelper";
|
static final String TAG = "com.android.systemui.SwipeHelper";
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
@@ -399,7 +401,7 @@ public class SwipeHelper implements Gefingerpoken {
|
|||||||
* @param useAccelerateInterpolator Should an accelerating Interpolator be used
|
* @param useAccelerateInterpolator Should an accelerating Interpolator be used
|
||||||
* @param fixedDuration If not 0, this exact duration will be taken
|
* @param fixedDuration If not 0, this exact duration will be taken
|
||||||
*/
|
*/
|
||||||
public void dismissChild(final View animView, float velocity, final Runnable endAction,
|
public void dismissChild(final View animView, float velocity, final Consumer<Boolean> endAction,
|
||||||
long delay, boolean useAccelerateInterpolator, long fixedDuration,
|
long delay, boolean useAccelerateInterpolator, long fixedDuration,
|
||||||
boolean isDismissAll) {
|
boolean isDismissAll) {
|
||||||
final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
|
final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
|
||||||
@@ -487,7 +489,7 @@ public class SwipeHelper implements Gefingerpoken {
|
|||||||
resetSwipeState();
|
resetSwipeState();
|
||||||
}
|
}
|
||||||
if (endAction != null) {
|
if (endAction != null) {
|
||||||
endAction.run();
|
endAction.accept(mCancelled);
|
||||||
}
|
}
|
||||||
if (!mDisableHwLayers) {
|
if (!mDisableHwLayers) {
|
||||||
animView.setLayerType(View.LAYER_TYPE_NONE, null);
|
animView.setLayerType(View.LAYER_TYPE_NONE, null);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar.notification.row;
|
package com.android.systemui.statusbar.notification.row;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
import android.animation.AnimatorListenerAdapter;
|
import android.animation.AnimatorListenerAdapter;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
@@ -25,6 +26,8 @@ import android.view.animation.Interpolator;
|
|||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.systemui.animation.Interpolators;
|
import com.android.systemui.animation.Interpolators;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A common base class for all views in the notification stack scroller which don't have a
|
* A common base class for all views in the notification stack scroller which don't have a
|
||||||
* background.
|
* background.
|
||||||
@@ -48,7 +51,7 @@ public abstract class StackScrollerDecorView extends ExpandableView {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private boolean mSecondaryAnimating = false;
|
private boolean mSecondaryAnimating = false;
|
||||||
private final Runnable mSecondaryVisibilityEndRunnable = () -> {
|
private final Consumer<Boolean> mSecondaryVisibilityEndRunnable = (cancelled) -> {
|
||||||
mSecondaryAnimating = false;
|
mSecondaryAnimating = false;
|
||||||
// If we were on screen, become GONE to avoid touches
|
// If we were on screen, become GONE to avoid touches
|
||||||
if (mSecondaryView == null) return;
|
if (mSecondaryView == null) return;
|
||||||
@@ -96,18 +99,20 @@ public abstract class StackScrollerDecorView extends ExpandableView {
|
|||||||
* @param animate True if we should fade to new visibility
|
* @param animate True if we should fade to new visibility
|
||||||
* @param runAfter Runnable to run after visibility updates
|
* @param runAfter Runnable to run after visibility updates
|
||||||
*/
|
*/
|
||||||
public void setContentVisible(boolean visible, boolean animate, Runnable runAfter) {
|
public void setContentVisible(boolean visible, boolean animate, Consumer<Boolean> runAfter) {
|
||||||
if (mContentVisible != visible) {
|
if (mContentVisible != visible) {
|
||||||
mContentAnimating = animate;
|
mContentAnimating = animate;
|
||||||
mContentVisible = visible;
|
mContentVisible = visible;
|
||||||
Runnable endRunnable = runAfter == null ? mContentVisibilityEndRunnable : () -> {
|
Consumer<Boolean> endRunnable = (cancelled) -> {
|
||||||
mContentVisibilityEndRunnable.run();
|
mContentVisibilityEndRunnable.run();
|
||||||
runAfter.run();
|
if (runAfter != null) {
|
||||||
|
runAfter.accept(cancelled);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
setViewVisible(mContent, visible, animate, endRunnable);
|
setViewVisible(mContent, visible, animate, endRunnable);
|
||||||
} else if (runAfter != null) {
|
} else if (runAfter != null) {
|
||||||
// Execute the runAfter runnable immediately if there's no animation to perform.
|
// Execute the runAfter runnable immediately if there's no animation to perform.
|
||||||
runAfter.run();
|
runAfter.accept(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mContentAnimating) {
|
if (!mContentAnimating) {
|
||||||
@@ -119,10 +124,6 @@ public abstract class StackScrollerDecorView extends ExpandableView {
|
|||||||
return mContentVisible;
|
return mContentVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVisible(boolean nowVisible, boolean animate) {
|
|
||||||
setVisible(nowVisible, animate, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make this view visible. If {@code false} is passed, the view will fade out it's content
|
* Make this view visible. If {@code false} is passed, the view will fade out it's content
|
||||||
* and set the view Visibility to GONE. If only the content should be changed
|
* and set the view Visibility to GONE. If only the content should be changed
|
||||||
@@ -131,7 +132,7 @@ public abstract class StackScrollerDecorView extends ExpandableView {
|
|||||||
* @param nowVisible should the view be visible
|
* @param nowVisible should the view be visible
|
||||||
* @param animate should the change be animated.
|
* @param animate should the change be animated.
|
||||||
*/
|
*/
|
||||||
public void setVisible(boolean nowVisible, boolean animate, Runnable runAfter) {
|
public void setVisible(boolean nowVisible, boolean animate) {
|
||||||
if (mIsVisible != nowVisible) {
|
if (mIsVisible != nowVisible) {
|
||||||
mIsVisible = nowVisible;
|
mIsVisible = nowVisible;
|
||||||
if (animate) {
|
if (animate) {
|
||||||
@@ -142,10 +143,10 @@ public abstract class StackScrollerDecorView extends ExpandableView {
|
|||||||
} else {
|
} else {
|
||||||
setWillBeGone(true);
|
setWillBeGone(true);
|
||||||
}
|
}
|
||||||
setContentVisible(nowVisible, true /* animate */, runAfter);
|
setContentVisible(nowVisible, true /* animate */, null /* runAfter */);
|
||||||
} else {
|
} else {
|
||||||
setVisibility(nowVisible ? VISIBLE : GONE);
|
setVisibility(nowVisible ? VISIBLE : GONE);
|
||||||
setContentVisible(nowVisible, false /* animate */, runAfter);
|
setContentVisible(nowVisible, false /* animate */, null /* runAfter */);
|
||||||
setWillBeGone(false);
|
setWillBeGone(false);
|
||||||
notifyHeightChanged(false /* needsAnimation */);
|
notifyHeightChanged(false /* needsAnimation */);
|
||||||
}
|
}
|
||||||
@@ -166,7 +167,7 @@ public abstract class StackScrollerDecorView extends ExpandableView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!mSecondaryAnimating) {
|
if (!mSecondaryAnimating) {
|
||||||
mSecondaryVisibilityEndRunnable.run();
|
mSecondaryVisibilityEndRunnable.accept(true /* cancelled */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +196,7 @@ public abstract class StackScrollerDecorView extends ExpandableView {
|
|||||||
* @param endRunnable A runnable that is run when the animation is done.
|
* @param endRunnable A runnable that is run when the animation is done.
|
||||||
*/
|
*/
|
||||||
private void setViewVisible(View view, boolean nowVisible,
|
private void setViewVisible(View view, boolean nowVisible,
|
||||||
boolean animate, Runnable endRunnable) {
|
boolean animate, Consumer<Boolean> endRunnable) {
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -211,7 +212,7 @@ public abstract class StackScrollerDecorView extends ExpandableView {
|
|||||||
if (!animate) {
|
if (!animate) {
|
||||||
view.setAlpha(endValue);
|
view.setAlpha(endValue);
|
||||||
if (endRunnable != null) {
|
if (endRunnable != null) {
|
||||||
endRunnable.run();
|
endRunnable.accept(true);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -222,7 +223,19 @@ public abstract class StackScrollerDecorView extends ExpandableView {
|
|||||||
.alpha(endValue)
|
.alpha(endValue)
|
||||||
.setInterpolator(interpolator)
|
.setInterpolator(interpolator)
|
||||||
.setDuration(mDuration)
|
.setDuration(mDuration)
|
||||||
.withEndAction(endRunnable);
|
.setListener(new AnimatorListenerAdapter() {
|
||||||
|
boolean mCancelled;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationCancel(Animator animation) {
|
||||||
|
mCancelled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
endRunnable.accept(mCancelled);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -231,7 +244,7 @@ public abstract class StackScrollerDecorView extends ExpandableView {
|
|||||||
Runnable onFinishedRunnable,
|
Runnable onFinishedRunnable,
|
||||||
AnimatorListenerAdapter animationListener) {
|
AnimatorListenerAdapter animationListener) {
|
||||||
// TODO: Use duration
|
// TODO: Use duration
|
||||||
setContentVisible(false, true /* animate */, onFinishedRunnable);
|
setContentVisible(false, true /* animate */, (cancelled) -> onFinishedRunnable.run());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1805,13 +1805,20 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
|
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
|
||||||
public void dismissViewAnimated(View child, Runnable endRunnable, int delay, long duration) {
|
public void dismissViewAnimated(
|
||||||
|
View child, Consumer<Boolean> endRunnable, int delay, long duration) {
|
||||||
if (child instanceof SectionHeaderView) {
|
if (child instanceof SectionHeaderView) {
|
||||||
((StackScrollerDecorView) child).setContentVisible(
|
((StackScrollerDecorView) child).setContentVisible(
|
||||||
false /* visible */, true /* animate */, endRunnable);
|
false /* visible */, true /* animate */, endRunnable);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mSwipeHelper.dismissChild(child, 0, endRunnable, delay, true, duration,
|
mSwipeHelper.dismissChild(
|
||||||
|
child,
|
||||||
|
0 /* velocity */,
|
||||||
|
endRunnable,
|
||||||
|
delay,
|
||||||
|
true /* useAccelerateInterpolator */,
|
||||||
|
duration,
|
||||||
true /* isClearAll */);
|
true /* isClearAll */);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5196,11 +5203,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
if (mClearAllListener != null) {
|
if (mClearAllListener != null) {
|
||||||
mClearAllListener.onClearAll(selection);
|
mClearAllListener.onClearAll(selection);
|
||||||
}
|
}
|
||||||
final Runnable dismissInBackend = () -> {
|
final Consumer<Boolean> dismissInBackend = (cancelled) -> {
|
||||||
|
if (cancelled) {
|
||||||
|
post(() -> onClearAllAnimationsEnd(rowsToDismissInBackend, selection));
|
||||||
|
} else {
|
||||||
onClearAllAnimationsEnd(rowsToDismissInBackend, selection);
|
onClearAllAnimationsEnd(rowsToDismissInBackend, selection);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
if (viewsToAnimateAway.isEmpty()) {
|
if (viewsToAnimateAway.isEmpty()) {
|
||||||
dismissInBackend.run();
|
dismissInBackend.accept(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Disable normal animations
|
// Disable normal animations
|
||||||
@@ -5215,7 +5226,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
final int numItems = viewsToAnimateAway.size();
|
final int numItems = viewsToAnimateAway.size();
|
||||||
for (int i = numItems - 1; i >= 0; i--) {
|
for (int i = numItems - 1; i >= 0; i--) {
|
||||||
View view = viewsToAnimateAway.get(i);
|
View view = viewsToAnimateAway.get(i);
|
||||||
Runnable endRunnable = null;
|
Consumer<Boolean> endRunnable = null;
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
endRunnable = dismissInBackend;
|
endRunnable = dismissInBackend;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user