Fill in ActivatableNotificationViewController.

This removes calls to Dependency.get() from
ActivatableNotificationView. The controller still isn't
fully fleshed out due to the current structure of the code,
but it is a step in the right direction.

Future CL's will add more controllers for futher subclasses.

Bug: 14724574
Test: atest SystemUITests
Change-Id: If72c1e19af69c41f9c557147e13593b33ba32bce
This commit is contained in:
Dave Mankoff
2020-01-21 19:15:14 -05:00
parent 6cd4ee4ce6
commit 514a84cf84
7 changed files with 258 additions and 122 deletions

View File

@@ -29,20 +29,17 @@ import android.util.MathUtils;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewAnimationUtils;
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 +91,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 +111,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 +125,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 +148,24 @@ 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;
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 +216,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) {
return true;
} else if (!mDoubleTapHelper.isWithinDoubleTapSlop(ev)) {
mBlockNextTouch = true;
makeInactive(true /* animate */);
return true;
}
if (mTouchHandler != null && mTouchHandler.onInterceptTouchEvent(ev)) {
return true;
}
return super.onInterceptTouchEvent(ev);
}
private boolean isTouchExplorationEnabled() {
return mAccessibilityManager.isTouchExplorationEnabled();
}
protected boolean disallowSingleClick(MotionEvent ev) {
return false;
}
@@ -270,25 +233,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 +257,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,15 +315,12 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
mBackgroundNormal.animate()
.alpha(reverse ? 0f : 1f)
.setInterpolator(alphaInterpolator)
.setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedFraction = animation.getAnimatedFraction();
if (reverse) {
animatedFraction = 1.0f - animatedFraction;
}
setNormalBackgroundVisibilityAmount(animatedFraction);
.setUpdateListener(animation -> {
float animatedFraction = animation.getAnimatedFraction();
if (reverse) {
animatedFraction = 1.0f - animatedFraction;
}
setNormalBackgroundVisibilityAmount(animatedFraction);
})
.setDuration(ACTIVATE_ANIMATION_LENGTH);
}
@@ -418,11 +342,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 +365,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 +403,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 +492,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) {
int newColor = NotificationUtils.interpolateColors(mStartTint, mTargetTint,
animation.getAnimatedFraction());
setBackgroundTintColor(newColor);
}
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 +570,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 +598,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 +709,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) {
mAppearAnimationFraction = (float) animation.getAnimatedValue();
updateAppearAnimationAlpha();
updateAppearRect();
invalidate();
}
mAppearAnimator.addUpdateListener(animation -> {
mAppearAnimationFraction = (float) animation.getAnimatedValue();
updateAppearAnimationAlpha();
updateAppearRect();
invalidate();
});
if (animationListener != null) {
mAppearAnimator.addListener(animationListener);
@@ -921,7 +844,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 +886,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
}
protected int getRippleColor() {
private int getRippleColor() {
if (mBgTint != 0) {
return mTintedRippleColor;
} else {
@@ -1010,10 +933,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 +990,20 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
return mRefocusOnDismiss || isAccessibilityFocused();
}
void setTouchHandler(Gefingerpoken touchHandler) {
mTouchHandler = touchHandler;
}
void setOnDimmedListener(OnDimmedListener onDimmedListener) {
mOnDimmedListener = onDimmedListener;
}
public interface OnActivatedListener {
void onActivated(ActivatableNotificationView view);
void onActivationReset(ActivatableNotificationView view);
}
interface OnDimmedListener {
void onSetDimmed(boolean dimmed);
}
}

View File

@@ -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,106 @@ 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;
if (dimmed && !mAccessibilityManager.isTouchExplorationEnabled()) {
mView.setOnClickListener(null);
} else {
mView.setOnClickListener((v) -> mView.performClick());
}
});
}
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;
}
}
}

View File

@@ -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());

View File

@@ -0,0 +1,41 @@
/*
* 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();
}
}

View File

@@ -0,0 +1,37 @@
/*
* 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() {
}
}

View File

@@ -32,7 +32,7 @@ import dagger.Subcomponent;
/**
* Dagger subcomponent for Notification related views.
*/
@Subcomponent(modules = {})
@Subcomponent(modules = {NotificationRowModule.class})
@NotificationRowComponent.NotificationRowScope
public interface NotificationRowComponent {
/**

View File

@@ -0,0 +1,37 @@
/*
* 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.dagger;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableOutlineView;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import dagger.Binds;
import dagger.Module;
/**
* Module for NotificationRowComponent.
*/
@Module
public interface NotificationRowModule {
/** ExpandableView is provided as an instance of ActivatableNotificationView. */
@Binds
ExpandableView bindExpandableView(ActivatableNotificationView view);
/** ExpandableOutlineView is provided as an instance of ActivatableNotificationView. */
@Binds
ExpandableOutlineView bindExpandableOutlineView(ActivatableNotificationView view);
}