Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a2c24e01 authored by Dave Mankoff's avatar Dave Mankoff
Browse files

Fill in ActivatableNotificationViewController.

This reverts commit 1a2744a4.

Prior commit had a bug related to clicking on notifications
that is now addressed.

Bug: 14724574
Test: atest SystemUITests
Change-Id: Ie1433a6e2c3095e31c9184032510b3db75de2ef3
parent 35bbc9d4
Loading
Loading
Loading
Loading
+65 −119
Original line number Diff line number Diff line
@@ -33,16 +33,14 @@ import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;

import com.android.systemui.Dependency;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.DoubleTapHelper;

/**
 * Base class for both {@link ExpandableNotificationRow} and {@link NotificationShelf}
@@ -94,14 +92,12 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
    private static final Interpolator ACTIVATE_INVERSE_ALPHA_INTERPOLATOR
            = new PathInterpolator(0, 0, 0.5f, 1);
    private int mTintedRippleColor;
    protected int mNormalRippleColor;
    private final AccessibilityManager mAccessibilityManager;
    private final DoubleTapHelper mDoubleTapHelper;
    private int mNormalRippleColor;
    private Gefingerpoken mTouchHandler;

    private boolean mDimmed;

    protected int mBgTint = NO_COLOR;
    private float mBgAlpha = 1f;
    int mBgTint = NO_COLOR;

    /**
     * Flag to indicate that the notification has been touched once and the second touch will
@@ -116,7 +112,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
    private Interpolator mCurrentAppearInterpolator;
    private Interpolator mCurrentAlphaInterpolator;

    protected NotificationBackgroundView mBackgroundNormal;
    NotificationBackgroundView mBackgroundNormal;
    private NotificationBackgroundView mBackgroundDimmed;
    private ObjectAnimator mBackgroundAnimator;
    private RectF mAppearAnimationRect = new RectF();
@@ -130,7 +126,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
    private boolean mLastInSection;
    private boolean mFirstInSection;
    private boolean mIsBelowSpeedBump;
    private final FalsingManager mFalsingManager;

    private float mNormalBackgroundVisibilityAmount;
    private float mDimmedBackgroundFadeInAmount = -1;
@@ -154,38 +149,25 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
     */
    private boolean mNeedsDimming;
    private int mDimmedAlpha;
    private boolean mBlockNextTouch;
    private boolean mIsHeadsUpAnimation;
    private int mHeadsUpAddStartLocation;
    private float mHeadsUpLocation;
    private boolean mIsAppearing;
    private boolean mDismissed;
    private boolean mRefocusOnDismiss;
    private OnDimmedListener mOnDimmedListener;
    private AccessibilityManager mAccessibilityManager;

    public ActivatableNotificationView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mSlowOutFastInInterpolator = new PathInterpolator(0.8f, 0.0f, 0.6f, 1.0f);
        mSlowOutLinearInInterpolator = new PathInterpolator(0.8f, 0.0f, 1.0f, 1.0f);
        mFalsingManager = Dependency.get(FalsingManager.class);  // TODO: inject into a controller.
        setClipChildren(false);
        setClipToPadding(false);
        updateColors();
        mAccessibilityManager = AccessibilityManager.getInstance(mContext);

        mDoubleTapHelper = new DoubleTapHelper(this, (active) -> {
            if (active) {
                makeActive();
            } else {
                makeInactive(true /* animate */);
            }
        }, super::performClick, this::handleSlideBack, mFalsingManager::onNotificationDoubleTap);
        initDimens();
    }

    public FalsingManager getFalsingManager() {
        return mFalsingManager;
    }

    private void updateColors() {
        mNormalColor = mContext.getColor(R.color.notification_material_background_color);
        mTintedRippleColor = mContext.getColor(
@@ -236,32 +218,15 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
        mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim);
    }

    private final Runnable mTapTimeoutRunnable = new Runnable() {
        @Override
        public void run() {
            makeInactive(true /* animate */);
        }
    };

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (mNeedsDimming && ev.getActionMasked() == MotionEvent.ACTION_DOWN
                && disallowSingleClick(ev) && !isTouchExplorationEnabled()) {
            if (!mActivated) {
        if (mTouchHandler != null && mTouchHandler.onInterceptTouchEvent(ev)) {
            return true;
            } else if (!mDoubleTapHelper.isWithinDoubleTapSlop(ev)) {
                mBlockNextTouch = true;
                makeInactive(true /* animate */);
                return true;
            }
        }
        return super.onInterceptTouchEvent(ev);
    }

    private boolean isTouchExplorationEnabled() {
        return mAccessibilityManager.isTouchExplorationEnabled();
    }

    protected boolean disallowSingleClick(MotionEvent ev) {
        return false;
    }
@@ -270,25 +235,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean result;
        if (mBlockNextTouch) {
            mBlockNextTouch = false;
            return false;
        }
        if (mNeedsDimming && !isTouchExplorationEnabled() && isInteractive()) {
            boolean wasActivated = mActivated;
            result = handleTouchEventDimmed(event);
            if (wasActivated && result && event.getAction() == MotionEvent.ACTION_UP) {
                removeCallbacks(mTapTimeoutRunnable);
            }
        } else {
            result = super.onTouchEvent(event);
        }
        return result;
    }

    /**
     * @return whether this view is interactive and can be double tapped
     */
@@ -313,28 +259,11 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
        }
    }

    public void setRippleAllowed(boolean allowed) {
    void setRippleAllowed(boolean allowed) {
        mBackgroundNormal.setPressedAllowed(allowed);
    }

    private boolean handleTouchEventDimmed(MotionEvent event) {
        if (mNeedsDimming && !mDimmed) {
            // We're actually dimmed, but our content isn't dimmable, let's ensure we have a ripple
            super.onTouchEvent(event);
        }
        return mDoubleTapHelper.onTouchEvent(event, getActualHeight());
    }

    @Override
    public boolean performClick() {
        if (!mNeedsDimming || isTouchExplorationEnabled()) {
            return super.performClick();
        }
        return false;
    }

    private void makeActive() {
        mFalsingManager.onNotificationActive();
    void makeActive() {
        startActivateAnimation(false /* reverse */);
        mActivated = true;
        if (mOnActivatedListener != null) {
@@ -388,19 +317,25 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
        mBackgroundNormal.animate()
                .alpha(reverse ? 0f : 1f)
                .setInterpolator(alphaInterpolator)
                .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                .setUpdateListener(animation -> {
                    float animatedFraction = animation.getAnimatedFraction();
                    if (reverse) {
                        animatedFraction = 1.0f - animatedFraction;
                    }
                    setNormalBackgroundVisibilityAmount(animatedFraction);
                    }
                })
                .setDuration(ACTIVATE_ANIMATION_LENGTH);
    }

    @Override
    public boolean performClick() {
        if (!mNeedsDimming || (mAccessibilityManager != null
                && mAccessibilityManager.isTouchExplorationEnabled())) {
            return super.performClick();
        }
        return false;
    }

    /**
     * Cancels the hotspot and makes the notification inactive.
     */
@@ -418,11 +353,13 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
        if (mOnActivatedListener != null) {
            mOnActivatedListener.onActivationReset(this);
        }
        removeCallbacks(mTapTimeoutRunnable);
    }

    public void setDimmed(boolean dimmed, boolean fade) {
        mNeedsDimming = dimmed;
        if (mOnDimmedListener != null) {
            mOnDimmedListener.onSetDimmed(dimmed);
        }
        dimmed &= isDimmable();
        if (mDimmed != dimmed) {
            mDimmed = dimmed;
@@ -439,13 +376,17 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
        return true;
    }

    public boolean isDimmed() {
        return mDimmed;
    }

    private void updateOutlineAlpha() {
        float alpha = NotificationStackScrollLayout.BACKGROUND_ALPHA_DIMMED;
        alpha = (alpha + (1.0f - alpha) * mNormalBackgroundVisibilityAmount);
        setOutlineAlpha(alpha);
    }

    public void setNormalBackgroundVisibilityAmount(float normalBackgroundVisibilityAmount) {
    private void setNormalBackgroundVisibilityAmount(float normalBackgroundVisibilityAmount) {
        mNormalBackgroundVisibilityAmount = normalBackgroundVisibilityAmount;
        updateOutlineAlpha();
    }
@@ -473,14 +414,14 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
    /**
     * Sets the tint color of the background
     */
    public void setTintColor(int color) {
    protected void setTintColor(int color) {
        setTintColor(color, false);
    }

    /**
     * Sets the tint color of the background
     */
    public void setTintColor(int color, boolean animated) {
    void setTintColor(int color, boolean animated) {
        if (color != mBgTint) {
            mBgTint = color;
            updateBackgroundTint(animated);
@@ -562,13 +503,10 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
            mStartTint = mCurrentBackgroundTint;
            mTargetTint = color;
            mBackgroundColorAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
            mBackgroundColorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
            mBackgroundColorAnimator.addUpdateListener(animation -> {
                int newColor = NotificationUtils.interpolateColors(mStartTint, mTargetTint,
                        animation.getAnimatedFraction());
                setBackgroundTintColor(newColor);
                }
            });
            mBackgroundColorAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
            mBackgroundColorAnimator.setInterpolator(Interpolators.LINEAR);
@@ -643,11 +581,11 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
    }

    protected void updateBackgroundAlpha(float transformationAmount) {
        mBgAlpha =  isChildInGroup() && mDimmed ? transformationAmount : 1f;
        float bgAlpha = isChildInGroup() && mDimmed ? transformationAmount : 1f;
        if (mDimmedBackgroundFadeInAmount != -1) {
            mBgAlpha *= mDimmedBackgroundFadeInAmount;
            bgAlpha *= mDimmedBackgroundFadeInAmount;
        }
        mBackgroundDimmed.setAlpha(mBgAlpha);
        mBackgroundDimmed.setAlpha(bgAlpha);
    }

    protected void resetBackgroundAlpha() {
@@ -671,7 +609,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
            mBackgroundDimmed.setVisibility(View.INVISIBLE);
            mBackgroundNormal.setVisibility(View.VISIBLE);
            mBackgroundNormal.setAlpha(1f);
            removeCallbacks(mTapTimeoutRunnable);
            // make in inactive to avoid it sticking around active
            makeInactive(false /* animate */);
        }
@@ -783,14 +720,11 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
        mAppearAnimator.setInterpolator(Interpolators.LINEAR);
        mAppearAnimator.setDuration(
                (long) (duration * Math.abs(mAppearAnimationFraction - targetValue)));
        mAppearAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
        mAppearAnimator.addUpdateListener(animation -> {
            mAppearAnimationFraction = (float) animation.getAnimatedValue();
            updateAppearAnimationAlpha();
            updateAppearRect();
            invalidate();
            }
        });
        if (animationListener != null) {
            mAppearAnimator.addListener(animationListener);
@@ -921,7 +855,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
                getCurrentBackgroundRadiusBottom());
    }

    protected void applyBackgroundRoundness(float topRadius, float bottomRadius) {
    private void applyBackgroundRoundness(float topRadius, float bottomRadius) {
        mBackgroundDimmed.setRoundness(topRadius, bottomRadius);
        mBackgroundNormal.setRoundness(topRadius, bottomRadius);
    }
@@ -963,7 +897,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
        }
    }

    protected int getRippleColor() {
    private int getRippleColor() {
        if (mBgTint != 0) {
            return mTintedRippleColor;
        } else {
@@ -1010,10 +944,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
        mOnActivatedListener = onActivatedListener;
    }

    public boolean hasSameBgColor(ActivatableNotificationView otherView) {
        return calculateBgColor() == otherView.calculateBgColor();
    }

    @Override
    public void setFakeShadowIntensity(float shadowIntensity, float outlineAlpha, int shadowYEnd,
            int outlineTranslation) {
@@ -1071,8 +1001,24 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
        return mRefocusOnDismiss || isAccessibilityFocused();
    }

    void setTouchHandler(Gefingerpoken touchHandler) {
        mTouchHandler = touchHandler;
    }

    void setOnDimmedListener(OnDimmedListener onDimmedListener) {
        mOnDimmedListener = onDimmedListener;
    }

    public void setAccessibilityManager(AccessibilityManager accessibilityManager) {
        mAccessibilityManager = accessibilityManager;
    }

    public interface OnActivatedListener {
        void onActivated(ActivatableNotificationView view);
        void onActivationReset(ActivatableNotificationView view);
    }

    interface OnDimmedListener {
        void onSetDimmed(boolean dimmed);
    }
}
+85 −0
Original line number Diff line number Diff line
@@ -16,9 +16,13 @@

package com.android.systemui.statusbar.notification.row;

import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityManager;

import com.android.systemui.Gefingerpoken;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.phone.DoubleTapHelper;

import javax.inject.Inject;

@@ -27,21 +31,102 @@ import javax.inject.Inject;
 */
public class ActivatableNotificationViewController {
    private final ActivatableNotificationView mView;
    private final ExpandableOutlineViewController mExpandableOutlineViewController;
    private final AccessibilityManager mAccessibilityManager;
    private final FalsingManager mFalsingManager;
    private DoubleTapHelper mDoubleTapHelper;
    private boolean mNeedsDimming;

    private TouchHandler mTouchHandler = new TouchHandler();

    @Inject
    public ActivatableNotificationViewController(ActivatableNotificationView view,
            ExpandableOutlineViewController expandableOutlineViewController,
            AccessibilityManager accessibilityManager, FalsingManager falsingManager) {
        mView = view;
        mExpandableOutlineViewController = expandableOutlineViewController;
        mAccessibilityManager = accessibilityManager;
        mFalsingManager = falsingManager;

        mView.setOnActivatedListener(new ActivatableNotificationView.OnActivatedListener() {
            @Override
            public void onActivated(ActivatableNotificationView view) {
                mFalsingManager.onNotificationActive();
            }

            @Override
            public void onActivationReset(ActivatableNotificationView view) {
            }
        });
    }

    /**
     * Initialize the controller, setting up handlers and other behavior.
     */
    public void init() {
        mExpandableOutlineViewController.init();
        mDoubleTapHelper = new DoubleTapHelper(mView, (active) -> {
            if (active) {
                mView.makeActive();
                mFalsingManager.onNotificationActive();
            } else {
                mView.makeInactive(true /* animate */);
            }
        }, mView::performClick, mView::handleSlideBack, mFalsingManager::onNotificationDoubleTap);
        mView.setOnTouchListener(mTouchHandler);
        mView.setTouchHandler(mTouchHandler);
        mView.setOnDimmedListener(dimmed -> {
            mNeedsDimming = dimmed;
        });
        mView.setAccessibilityManager(mAccessibilityManager);
    }

    class TouchHandler implements Gefingerpoken, View.OnTouchListener {
        private boolean mBlockNextTouch;

        @Override
        public boolean onTouch(View v, MotionEvent ev) {
            boolean result;
            if (mBlockNextTouch) {
                mBlockNextTouch = false;
                return true;
            }
            if (mNeedsDimming && !mAccessibilityManager.isTouchExplorationEnabled()
                    && mView.isInteractive()) {
                if (mNeedsDimming && !mView.isDimmed()) {
                    // We're actually dimmed, but our content isn't dimmable,
                    // let's ensure we have a ripple
                    return false;
                }
                result = mDoubleTapHelper.onTouchEvent(ev, mView.getActualHeight());
            } else {
                return false;
            }
            return result;
        }

        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            if (mNeedsDimming && ev.getActionMasked() == MotionEvent.ACTION_DOWN
                    && mView.disallowSingleClick(ev)
                    && !mAccessibilityManager.isTouchExplorationEnabled()) {
                if (!mView.isActivated()) {
                    return true;
                } else if (!mDoubleTapHelper.isWithinDoubleTapSlop(ev)) {
                    mBlockNextTouch = true;
                    mView.makeInactive(true /* animate */);
                    return true;
                }
            }
            return false;
        }

        /**
         * Use {@link #onTouch(View, MotionEvent) instead}.
         */
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            return false;
        }
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@ import com.android.internal.widget.CachingIconView;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
@@ -2188,7 +2189,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
     * @param allowChildExpansion whether a call to this method allows expanding children
     */
    public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
        getFalsingManager().setNotificationExpanded();
        Dependency.get(FalsingManager.class).setNotificationExpanded();
        if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion
                && !mChildrenContainer.showingAsLowPriority()) {
            final boolean wasExpanded = mGroupManager.isGroupExpanded(mEntry.getSbn());
+41 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.systemui.statusbar.notification.row;

import javax.inject.Inject;

/**
 * Controller for {@link ExpandableOutlineView}.
 */
public class ExpandableOutlineViewController {
    private final ExpandableOutlineView mView;
    private final ExpandableViewController mExpandableViewController;

    @Inject
    public ExpandableOutlineViewController(ExpandableOutlineView view,
            ExpandableViewController expandableViewController) {
        mView = view;
        mExpandableViewController = expandableViewController;
    }

    /**
     * Initialize the controller.
     */
    public void init() {
        mExpandableViewController.init();
    }
}
+37 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.systemui.statusbar.notification.row;

import javax.inject.Inject;

/**
 * Controller for {@link ExpandableView}.
 */
public class ExpandableViewController {
    private final ExpandableView mView;

    @Inject
    public ExpandableViewController(ExpandableView view) {
        mView = view;
    }

    /**
     * Initialize the controller.
     */
    public void init() {
    }
}
Loading