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

Commit 4222d9a7 authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Change interaction for dragging down to full shade.

Starts expanding the card if it is expandable. If it's not, we
rubberband the expansion a lot. After the threshold has been reached,
we scale all the notifications up and make it fully white and opaque.

Change-Id: I9ecd020ca263b0f84e87fd6ab2332519ac5e9984
parent ecbab366
Loading
Loading
Loading
Loading
+11 −48
Original line number Diff line number Diff line
@@ -29,17 +29,16 @@ import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewConfiguration;

import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.policy.ScrollAdapter;

public class ExpandHelper implements Gefingerpoken, OnClickListener {
public class ExpandHelper implements Gefingerpoken {
    public interface Callback {
        View getChildAtRawPosition(float x, float y);
        View getChildAtPosition(float x, float y);
        ExpandableView getChildAtRawPosition(float x, float y);
        ExpandableView getChildAtPosition(float x, float y);
        boolean canChildBeExpanded(View v);
        void setUserExpandedChild(View v, boolean userExpanded);
        void setUserLockedChild(View v, boolean userLocked);
@@ -48,9 +47,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
    private static final String TAG = "ExpandHelper";
    protected static final boolean DEBUG = false;
    protected static final boolean DEBUG_SCALE = false;
    protected static final boolean DEBUG_GLOW = false;
    private static final long EXPAND_DURATION = 250;
    private static final long GLOW_DURATION = 150;

    // Set to false to disable focus-based gestures (spread-finger vertical pull).
    private static final boolean USE_DRAG = true;
@@ -115,7 +112,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
            float focusX = detector.getFocusX();
            float focusY = detector.getFocusY();

            final View underFocus = findView(focusX, focusY);
            final ExpandableView underFocus = findView(focusX, focusY);
            startExpanding(underFocus, STRETCH);
            return mExpanding;
        }
@@ -172,24 +169,6 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
        mPopDuration = mContext.getResources().getInteger(R.integer.blinds_pop_duration_ms);
        mPullGestureMinXSpan = mContext.getResources().getDimension(R.dimen.pull_span_min);

        AnimatorListenerAdapter glowVisibilityController = new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                View target = (View) ((ObjectAnimator) animation).getTarget();
                if (target.getAlpha() <= 0.0f) {
                    target.setVisibility(View.VISIBLE);
                }
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                View target = (View) ((ObjectAnimator) animation).getTarget();
                if (target.getAlpha() <= 0.0f) {
                    target.setVisibility(View.INVISIBLE);
                }
            }
        };

        final ViewConfiguration configuration = ViewConfiguration.get(mContext);
        mTouchSlop = configuration.getScaledTouchSlop();

@@ -221,8 +200,8 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
        return out;
    }

    private View findView(float x, float y) {
        View v = null;
    private ExpandableView findView(float x, float y) {
        ExpandableView v;
        if (mEventSource != null) {
            int[] location = new int[2];
            mEventSource.getLocationOnScreen(location);
@@ -271,15 +250,6 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
        mScrollAdapter = adapter;
    }

    private float calculateGlow(float target, float actual) {
        // glow if overscale
        if (DEBUG_GLOW) Log.d(TAG, "target: " + target + " actual: " + actual);
        float stretch = Math.abs((target - actual) / mMaximumStretch);
        float strength = 1f / (1f + (float) Math.pow(Math.E, -1 * ((8f * stretch) - 5f)));
        if (DEBUG_GLOW) Log.d(TAG, "stretch: " + stretch + " strength: " + strength);
        return (GLOW_BASE + strength * (1f - GLOW_BASE));
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();
@@ -313,7 +283,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
                // detect a vertical pulling gesture with fingers somewhat separated
                if (DEBUG_SCALE) Log.v(TAG, "got pull gesture (xspan=" + xspan + "px)");

                final View underFocus = findView(x, y);
                final ExpandableView underFocus = findView(x, y);
                startExpanding(underFocus, PULL);
                return true;
            }
@@ -328,7 +298,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
                    if (yDiff > mTouchSlop) {
                        if (DEBUG) Log.v(TAG, "got venetian gesture (dy=" + yDiff + "px)");
                        mLastMotionY = y;
                        final View underFocus = findView(x, y);
                        final ExpandableView underFocus = findView(x, y);
                        if (startExpanding(underFocus, BLINDS)) {
                            mInitialTouchY = mLastMotionY;
                            mHasPopped = false;
@@ -394,7 +364,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {

                    final int x = (int) mSGD.getFocusX();
                    final int y = (int) mSGD.getFocusY();
                    View underFocus = findView(x, y);
                    ExpandableView underFocus = findView(x, y);
                    if (isFinished && underFocus != null && underFocus != mCurrView) {
                        finishExpanding(false); // @@@ needed?
                        startExpanding(underFocus, BLINDS);
@@ -432,7 +402,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
    /**
     * @return True if the view is expandable, false otherwise.
     */
    private boolean startExpanding(View v, int expandType) {
    private boolean startExpanding(ExpandableView v, int expandType) {
        if (!(v instanceof ExpandableNotificationRow)) {
            return false;
        }
@@ -512,13 +482,6 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
        mCurrView = v;
    }

    @Override
    public void onClick(View v) {
        startExpanding(v, STRETCH);
        finishExpanding(true);
        clearView();
    }

    /**
     * Use this to abort any pending expansions in progress.
     */
+150 −22
Original line number Diff line number Diff line
@@ -16,12 +16,18 @@

package com.android.systemui.statusbar;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.FrameLayout;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;

import com.android.internal.R;

@@ -34,7 +40,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
    private static final long DOUBLETAP_TIMEOUT_MS = 1000;

    private boolean mDimmed;
    private boolean mLocked;

    private int mBgResId = R.drawable.notification_quantum_bg;
    private int mDimmedBgResId = R.drawable.notification_quantum_bg_dim;
@@ -51,13 +56,20 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView

    private OnActivatedListener mOnActivatedListener;

    protected Drawable mBackgroundNormal;
    protected Drawable mBackgroundDimmed;
    private ObjectAnimator mBackgroundAnimator;
    private Interpolator mFastOutSlowInInterpolator;

    public ActivatableNotificationView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        updateBackgroundResource();
        setWillNotDraw(false);
        mFastOutSlowInInterpolator =
                AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
    }


    private final Runnable mTapTimeoutRunnable = new Runnable() {
        @Override
        public void run() {
@@ -65,6 +77,37 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
        }
    };

    @Override
    protected void onDraw(Canvas canvas) {
        draw(canvas, mBackgroundNormal);
        draw(canvas, mBackgroundDimmed);
    }

    private void draw(Canvas canvas, Drawable drawable) {
        if (drawable != null) {
            drawable.setBounds(0, mClipTopAmount, getWidth(), mActualHeight);
            drawable.draw(canvas);
        }
    }

    @Override
    protected boolean verifyDrawable(Drawable who) {
        return super.verifyDrawable(who) || who == mBackgroundNormal
                || who == mBackgroundDimmed;
    }

    @Override
    protected void drawableStateChanged() {
        drawableStateChanged(mBackgroundNormal);
        drawableStateChanged(mBackgroundDimmed);
    }

    private void drawableStateChanged(Drawable d) {
        if (d != null && d.isStateful()) {
            d.setState(getDrawableState());
        }
    }

    @Override
    public void setOnClickListener(OnClickListener l) {
        super.setOnClickListener(l);
@@ -72,14 +115,14 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mLocked) {
            return handleTouchEventLocked(event);
        if (mDimmed) {
            return handleTouchEventDimmed(event);
        } else {
            return super.onTouchEvent(event);
        }
    }

    private boolean handleTouchEventLocked(MotionEvent event) {
    private boolean handleTouchEventDimmed(MotionEvent event) {
        int action = event.getActionMasked();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
@@ -118,7 +161,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
    }

    private void makeActive(float x, float y) {
        mCustomBackground.setHotspot(0, x, y);
        mBackgroundDimmed.setHotspot(0, x, y);
        mActivated = true;
        if (mOnActivatedListener != null) {
            mOnActivatedListener.onActivated(this);
@@ -131,8 +174,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
    private void makeInactive() {
        if (mActivated) {
            // Make sure that we clear the hotspot from the center.
            mCustomBackground.setHotspot(0, getWidth() / 2, getActualHeight() / 2);
            mCustomBackground.removeHotspot(0);
            mBackgroundDimmed.setHotspot(0, getWidth() / 2, getActualHeight() / 2);
            mBackgroundDimmed.removeHotspot(0);
            mActivated = false;
        }
        if (mOnActivatedListener != null) {
@@ -148,20 +191,19 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView

    /**
     * Sets the notification as dimmed, meaning that it will appear in a more gray variant.
     *
     * @param dimmed Whether the notification should be dimmed.
     * @param fade Whether an animation should be played to change the state.
     */
    public void setDimmed(boolean dimmed) {
    public void setDimmed(boolean dimmed, boolean fade) {
        if (mDimmed != dimmed) {
            mDimmed = dimmed;
            if (fade) {
                fadeBackgroundResource();
            } else {
                updateBackgroundResource();
            }
        }

    /**
     * Sets the notification as locked. In the locked state, the first tap will produce a quantum
     * ripple to make the notification brighter and only the second tap will cause a click.
     */
    public void setLocked(boolean locked) {
        mLocked = locked;
    }

    /**
@@ -176,8 +218,87 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
        updateBackgroundResource();
    }

    private void fadeBackgroundResource() {
        if (mDimmed) {
            setBackgroundDimmed(mDimmedBgResId);
        } else {
            setBackgroundNormal(mBgResId);
        }
        int startAlpha = mDimmed ? 255 : 0;
        int endAlpha = mDimmed ? 0 : 255;
        int duration = NotificationActivator.ANIMATION_LENGTH_MS;
        // Check whether there is already a background animation running.
        if (mBackgroundAnimator != null) {
            startAlpha = (Integer) mBackgroundAnimator.getAnimatedValue();
            duration = (int) (NotificationActivator.ANIMATION_LENGTH_MS
                                - mBackgroundAnimator.getCurrentPlayTime());
            mBackgroundAnimator.removeAllListeners();
            mBackgroundAnimator.cancel();
        }
        mBackgroundNormal.setAlpha(startAlpha);
        mBackgroundAnimator =
                ObjectAnimator.ofInt(mBackgroundNormal, "alpha", startAlpha, endAlpha);
        mBackgroundAnimator.setInterpolator(mFastOutSlowInInterpolator);
        mBackgroundAnimator.setDuration(duration);
        mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                if (mDimmed) {
                    setBackgroundNormal(null);
                } else {
                    setBackgroundDimmed(null);
                }
                mBackgroundAnimator = null;
            }
        });
        mBackgroundAnimator.start();
    }

    private void updateBackgroundResource() {
        setCustomBackgroundResource(mDimmed ? mDimmedBgResId : mBgResId);
        if (mDimmed) {
            setBackgroundDimmed(mDimmedBgResId);
            setBackgroundNormal(null);
        } else {
            setBackgroundDimmed(null);
            setBackgroundNormal(mBgResId);
        }
    }

    /**
     * Sets a background drawable for the normal state. As we need to change our bounds
     * independently of layout, we need the notion of a background independently of the regular View
     * background..
     */
    private void setBackgroundNormal(Drawable backgroundNormal) {
        if (mBackgroundNormal != null) {
            mBackgroundNormal.setCallback(null);
            unscheduleDrawable(mBackgroundNormal);
        }
        mBackgroundNormal = backgroundNormal;
        if (mBackgroundNormal != null) {
            mBackgroundNormal.setCallback(this);
        }
        invalidate();
    }

    private void setBackgroundDimmed(Drawable overlay) {
        if (mBackgroundDimmed != null) {
            mBackgroundDimmed.setCallback(null);
            unscheduleDrawable(mBackgroundDimmed);
        }
        mBackgroundDimmed = overlay;
        if (mBackgroundDimmed != null) {
            mBackgroundDimmed.setCallback(this);
        }
        invalidate();
    }

    private void setBackgroundNormal(int drawableResId) {
        setBackgroundNormal(getResources().getDrawable(drawableResId));
    }

    private void setBackgroundDimmed(int drawableResId) {
        setBackgroundDimmed(getResources().getDrawable(drawableResId));
    }

    @Override
@@ -189,9 +310,16 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
    @Override
    public void setActualHeight(int actualHeight) {
        super.setActualHeight(actualHeight);
        invalidate();
        setPivotY(actualHeight / 2);
    }

    @Override
    public void setClipTopAmount(int clipTopAmount) {
        super.setClipTopAmount(clipTopAmount);
        invalidate();
    }

    public void setOnActivatedListener(OnActivatedListener onActivatedListener) {
        mOnActivatedListener = onActivatedListener;
    }
+14 −2
Original line number Diff line number Diff line
@@ -171,6 +171,7 @@ public abstract class BaseStatusBar extends SystemUI implements
     * The {@link StatusBarState} of the status bar.
     */
    protected int mState;
    protected boolean mBouncerShowing;

    protected NotificationOverflowContainer mKeyguardIconOverflowContainer;

@@ -1073,8 +1074,7 @@ public abstract class BaseStatusBar extends SystemUI implements
                    entry.row.setSystemExpanded(top);
                }
            }
            entry.row.setDimmed(onKeyguard);
            entry.row.setLocked(onKeyguard);
            entry.row.setDimmed(onKeyguard, false /* fade */);
            boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
            if (onKeyguard && (visibleNotifications >= maxKeyguardNotifications
                    || !showOnKeyguard)) {
@@ -1094,6 +1094,7 @@ public abstract class BaseStatusBar extends SystemUI implements

        if (onKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) {
            mKeyguardIconOverflowContainer.setVisibility(View.VISIBLE);
            mKeyguardIconOverflowContainer.setDimmed(true /* dimmed */, false /* fade */);
        } else {
            mKeyguardIconOverflowContainer.setVisibility(View.GONE);
        }
@@ -1403,6 +1404,17 @@ public abstract class BaseStatusBar extends SystemUI implements
        // hook for subclasses
    }

    public void setBouncerShowing(boolean bouncerShowing) {
        mBouncerShowing = bouncerShowing;
    }

    /**
     * @return Whether the security bouncer from Keyguard is showing.
     */
    public boolean isBouncerShowing() {
        return mBouncerShowing;
    }

    public void destroy() {
        if (mSearchPanelView != null) {
            mWindowManager.removeViewImmediate(mSearchPanelView);
+67 −20
Original line number Diff line number Diff line
@@ -16,24 +16,31 @@

package com.android.systemui.statusbar;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.util.ArraySet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;

import com.android.systemui.ExpandHelper;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;

import java.util.HashSet;

/**
 * A utility class to enable the downward swipe on the lockscreen to go to the full shade and expand
 * the notification where the drag started.
 */
public class DragDownHelper implements Gefingerpoken {

    private static final float RUBBERBAND_FACTOR_EXPANDABLE = 0.5f;
    private static final float RUBBERBAND_FACTOR_STATIC = 0.15f;

    private static final int SPRING_BACK_ANIMATION_LENGTH_MS = 375;

    private int mMinDragDistance;
    private ExpandHelper.Callback mCallback;
    private float mInitialTouchX;
@@ -43,14 +50,16 @@ public class DragDownHelper implements Gefingerpoken {
    private OnDragDownListener mOnDragDownListener;
    private View mHost;
    private final int[] mTemp2 = new int[2];
    private final ArraySet<View> mHoveredChildren = new ArraySet<View>();
    private boolean mDraggedFarEnough;
    private View mStartingChild;
    private ExpandableView mStartingChild;
    private Interpolator mInterpolator;

    public DragDownHelper(Context context, View host, ExpandHelper.Callback callback,
            OnDragDownListener onDragDownListener) {
        mMinDragDistance = context.getResources().getDimensionPixelSize(
                R.dimen.keyguard_drag_down_min_distance);
        mInterpolator =
                AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        mCallback = callback;
        mOnDragDownListener = onDragDownListener;
@@ -64,7 +73,6 @@ public class DragDownHelper implements Gefingerpoken {

        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                mHoveredChildren.clear();
                mDraggedFarEnough = false;
                mDraggingDown = false;
                mStartingChild = null;
@@ -76,6 +84,7 @@ public class DragDownHelper implements Gefingerpoken {
                final float h = y - mInitialTouchY;
                if (h > mTouchSlop && h > Math.abs(x - mInitialTouchX)) {
                    mDraggingDown = true;
                    captureStartingChild(mInitialTouchX, mInitialTouchY);
                    mInitialTouchY = y;
                    mInitialTouchX = x;
                    return true;
@@ -96,9 +105,9 @@ public class DragDownHelper implements Gefingerpoken {
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_MOVE:
                final float h = y - mInitialTouchY;
                View child = findView(x, y);
                if (child != null) {
                    hoverChild(findView(x, y));
                captureStartingChild(mInitialTouchX, mInitialTouchY);
                if (mStartingChild != null) {
                    handleExpansion(h, mStartingChild);
                }
                if (h > mMinDragDistance) {
                    if (!mDraggedFarEnough) {
@@ -114,6 +123,9 @@ public class DragDownHelper implements Gefingerpoken {
                return true;
            case MotionEvent.ACTION_UP:
                if (mDraggedFarEnough) {
                    if (mStartingChild != null) {
                        mCallback.setUserLockedChild(mStartingChild, false);
                    }
                    mOnDragDownListener.onDraggedDown(mStartingChild);
                } else {
                    stopDragging();
@@ -127,22 +139,58 @@ public class DragDownHelper implements Gefingerpoken {
        return false;
    }

    private void stopDragging() {
        mDraggingDown = false;
        mOnDragDownListener.onReset();
    private void captureStartingChild(float x, float y) {
        if (mStartingChild == null) {
            mStartingChild = findView(x, y);
            if (mStartingChild != null) {
                mCallback.setUserLockedChild(mStartingChild, true);
            }
        }
    }

    private void handleExpansion(float heightDelta, ExpandableView child) {
        if (heightDelta < 0) {
            heightDelta = 0;
        }
        boolean expandable = child.isContentExpandable();
        float rubberbandFactor = expandable
                ? RUBBERBAND_FACTOR_EXPANDABLE
                : RUBBERBAND_FACTOR_STATIC;
        float rubberband = heightDelta * rubberbandFactor;
        if (expandable && (rubberband + child.getMinHeight()) > child.getMaxHeight()) {
            float overshoot = (rubberband + child.getMinHeight()) - child.getMaxHeight();
            overshoot *= (1 - RUBBERBAND_FACTOR_STATIC);
            rubberband -= overshoot;
        }
        child.setActualHeight((int) (child.getMinHeight() + rubberband));
    }

    private void hoverChild(View child) {
        if (mHoveredChildren.isEmpty()) {
            mStartingChild = child;
    private void cancelExpansion(final ExpandableView child) {
        if (child.getActualHeight() == child.getMinHeight()) {
            return;
        }
        ObjectAnimator anim = ObjectAnimator.ofInt(child, "actualHeight",
                child.getActualHeight(), child.getMinHeight());
        anim.setInterpolator(mInterpolator);
        anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS);
        anim.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mCallback.setUserLockedChild(child, false);
            }
        if (!mHoveredChildren.contains(child)) {
            mOnDragDownListener.onHover(child);
            mHoveredChildren.add(child);
        });
        anim.start();
    }

    private void stopDragging() {
        if (mStartingChild != null) {
            cancelExpansion(mStartingChild);
        }
        mDraggingDown = false;
        mOnDragDownListener.onReset();
    }

    private View findView(float x, float y) {
    private ExpandableView findView(float x, float y) {
        mHost.getLocationOnScreen(mTemp2);
        x += mTemp2[0];
        y += mTemp2[1];
@@ -150,7 +198,6 @@ public class DragDownHelper implements Gefingerpoken {
    }

    public interface OnDragDownListener {
        void onHover(View child);
        void onDraggedDown(View startingChild);
        void onReset();
        void onThresholdReached();
+15 −7
Original line number Diff line number Diff line
@@ -23,8 +23,7 @@ import android.view.accessibility.AccessibilityEvent;

import com.android.systemui.R;

public class ExpandableNotificationRow extends ActivatableNotificationView implements
        NotificationActivatable {
public class ExpandableNotificationRow extends ActivatableNotificationView {
    private int mRowMinHeight;
    private int mRowMaxHeight;

@@ -114,7 +113,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView imple
    public void setUserExpanded(boolean userExpanded) {
        mHasUserChangedExpansion = true;
        mUserExpanded = userExpanded;
        applyExpansionToLayout();
    }

    public boolean isUserLocked() {
@@ -218,16 +216,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView imple
    /**
     * Sets the notification as dimmed, meaning that it will appear in a more gray variant.
     */
    public void setDimmed(boolean dimmed) {
        super.setDimmed(dimmed);
        mActivator.setDimmed(dimmed);
    @Override
    public void setDimmed(boolean dimmed, boolean fade) {
        super.setDimmed(dimmed, fade);
        mActivator.setDimmed(dimmed, fade);
    }

    public int getMaxExpandHeight() {
        return mMaxExpandHeight;
    }

    @Override
    public NotificationActivator getActivator() {
        return mActivator;
    }
@@ -239,6 +237,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView imple
        return getMaximumAllowedExpandHeight() - getActualHeight();
    }

    @Override
    public boolean isContentExpandable() {
        return mPrivateLayout.isContentExpandable();
    }

    @Override
    public void setActualHeight(int height) {
        mPrivateLayout.setActualHeight(height);
@@ -251,6 +254,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView imple
        return mPrivateLayout.getMaxHeight();
    }

    @Override
    public int getMinHeight() {
        return mPrivateLayout.getMinHeight();
    }

    @Override
    public void setClipTopAmount(int clipTopAmount) {
        super.setClipTopAmount(clipTopAmount);
Loading