diff options
Diffstat (limited to 'src/com/android/launcher3/notification/NotificationMainView.java')
-rw-r--r-- | src/com/android/launcher3/notification/NotificationMainView.java | 231 |
1 files changed, 189 insertions, 42 deletions
diff --git a/src/com/android/launcher3/notification/NotificationMainView.java b/src/com/android/launcher3/notification/NotificationMainView.java index b8aa8246fb..f9ff8a6e56 100644 --- a/src/com/android/launcher3/notification/NotificationMainView.java +++ b/src/com/android/launcher3/notification/NotificationMainView.java @@ -16,62 +16,70 @@ package com.android.launcher3.notification; +import static com.android.launcher3.Utilities.mapToRange; +import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DISMISSED; import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.TargetApi; import android.content.Context; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; +import android.graphics.Outline; +import android.graphics.Rect; +import android.graphics.drawable.GradientDrawable; import android.os.Build; import android.text.TextUtils; import android.util.AttributeSet; -import android.util.FloatProperty; import android.view.View; import android.view.ViewGroup; -import android.widget.FrameLayout; +import android.view.ViewOutlineProvider; +import android.widget.LinearLayout; import android.widget.TextView; +import androidx.annotation.Nullable; + import com.android.launcher3.Launcher; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.touch.SingleAxisSwipeDetector; +import com.android.launcher3.util.Themes; /** * A {@link android.widget.FrameLayout} that contains a single notification, * e.g. icon + title + text. */ @TargetApi(Build.VERSION_CODES.N) -public class NotificationMainView extends FrameLayout { - - private static final FloatProperty<NotificationMainView> CONTENT_TRANSLATION = - new FloatProperty<NotificationMainView>("contentTranslation") { - @Override - public void setValue(NotificationMainView view, float v) { - view.setContentTranslation(v); - } - - @Override - public Float get(NotificationMainView view) { - return view.mTextAndBackground.getTranslationX(); - } - }; +public class NotificationMainView extends LinearLayout { // This is used only to track the notification view, so that it can be properly logged. public static final ItemInfo NOTIFICATION_ITEM_INFO = new ItemInfo(); + // Value when the primary notification main view will be gone (zero alpha). + private static final float PRIMARY_GONE_PROGRESS = 0.7f; + private static final float PRIMARY_MIN_PROGRESS = 0.40f; + private static final float PRIMARY_MAX_PROGRESS = 0.60f; + private static final float SECONDARY_MIN_PROGRESS = 0.30f; + private static final float SECONDARY_MAX_PROGRESS = 0.50f; + private static final float SECONDARY_CONTENT_MAX_PROGRESS = 0.6f; + private NotificationInfo mNotificationInfo; - private ViewGroup mTextAndBackground; private int mBackgroundColor; private TextView mTitleView; private TextView mTextView; private View mIconView; - private SingleAxisSwipeDetector mSwipeDetector; + private View mHeader; + private View mMainView; + + private TextView mHeaderCount; + private final Rect mOutline = new Rect(); - private final ColorDrawable mColorDrawable; + // Space between notifications during swipe + private final int mNotificationSpace; + private final int mMaxTransX; + private final int mMaxElevation; + + private final GradientDrawable mBackground; public NotificationMainView(Context context) { this(context, null, 0); @@ -82,28 +90,77 @@ public class NotificationMainView extends FrameLayout { } public NotificationMainView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); + this(context, attrs, defStyle, 0); + } + + public NotificationMainView(Context context, AttributeSet attrs, int defStyle, int defStylRes) { + super(context, attrs, defStyle, defStylRes); + + float outlineRadius = Themes.getDialogCornerRadius(context); + + mBackground = new GradientDrawable(); + mBackground.setColor(Themes.getAttrColor(context, R.attr.popupColorPrimary)); + mBackground.setCornerRadius(outlineRadius); + setBackground(mBackground); + + mMaxElevation = getResources().getDimensionPixelSize(R.dimen.deep_shortcuts_elevation); + setElevation(mMaxElevation); + + mMaxTransX = getResources().getDimensionPixelSize(R.dimen.notification_max_trans); + mNotificationSpace = getResources().getDimensionPixelSize(R.dimen.notification_space); - mColorDrawable = new ColorDrawable(Color.TRANSPARENT); + setClipToOutline(true); + setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(mOutline, outlineRadius); + } + }); + } + + /** + * Updates the header text. + * @param notificationCount The number of notifications. + */ + public void updateHeader(int notificationCount) { + final String text; + final int visibility; + if (notificationCount <= 1) { + text = ""; + visibility = View.INVISIBLE; + } else { + text = String.valueOf(notificationCount); + visibility = View.VISIBLE; + + } + mHeaderCount.setText(text); + mHeaderCount.setVisibility(visibility); } @Override protected void onFinishInflate() { super.onFinishInflate(); - mTextAndBackground = findViewById(R.id.text_and_background); - mTitleView = mTextAndBackground.findViewById(R.id.title); - mTextView = mTextAndBackground.findViewById(R.id.text); + ViewGroup textAndBackground = findViewById(R.id.text_and_background); + mTitleView = textAndBackground.findViewById(R.id.title); + mTextView = textAndBackground.findViewById(R.id.text); mIconView = findViewById(R.id.popup_item_icon); + mHeaderCount = findViewById(R.id.notification_count); + + mHeader = findViewById(R.id.header); + mMainView = findViewById(R.id.main_view); + } - ColorDrawable colorBackground = (ColorDrawable) mTextAndBackground.getBackground(); - updateBackgroundColor(colorBackground.getColor()); + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + mOutline.set(0, 0, getWidth(), getHeight()); + invalidateOutline(); } private void updateBackgroundColor(int color) { mBackgroundColor = color; - mColorDrawable.setColor(color); - mTextAndBackground.setBackground(mColorDrawable); + mBackground.setColor(color); if (mNotificationInfo != null) { mIconView.setBackground(mNotificationInfo.getIconForBackground(getContext(), mBackgroundColor)); @@ -128,8 +185,11 @@ public class NotificationMainView extends FrameLayout { /** * Sets the content of this view, animating it after a new icon shifts up if necessary. */ - public void applyNotificationInfo(NotificationInfo mainNotification, boolean animate) { - mNotificationInfo = mainNotification; + public void applyNotificationInfo(NotificationInfo notificationInfo) { + mNotificationInfo = notificationInfo; + if (notificationInfo == null) { + return; + } NotificationListener listener = NotificationListener.getInstanceIfConnected(); if (listener != null) { listener.setNotificationsShown(new String[] {mNotificationInfo.notificationKey}); @@ -149,25 +209,112 @@ public class NotificationMainView extends FrameLayout { if (mNotificationInfo.intent != null) { setOnClickListener(mNotificationInfo); } - setContentTranslation(0); + // Add a stub ItemInfo so that logging populates the correct container and item types // instead of DEFAULT_CONTAINERTYPE and DEFAULT_ITEMTYPE, respectively. setTag(NOTIFICATION_ITEM_INFO); - if (animate) { - ObjectAnimator.ofFloat(mTextAndBackground, ALPHA, 0, 1).setDuration(150).start(); + } + + /** + * Sets the alpha of only the child views. + */ + public void setContentAlpha(float alpha) { + mHeader.setAlpha(alpha); + mMainView.setAlpha(alpha); + } + + /** + * Sets the translation of only the child views. + */ + public void setContentTranslationX(float transX) { + mHeader.setTranslationX(transX); + mMainView.setTranslationX(transX); + } + + /** + * Updates the alpha, content alpha, and elevation of this view. + * + * @param progress Range from [0, 1] or [-1, 0] + * When 0: Full alpha + * When 1/-1: zero alpha + */ + public void onPrimaryDrag(float progress) { + float absProgress = Math.abs(progress); + final int width = getWidth(); + + float min = PRIMARY_MIN_PROGRESS; + float max = PRIMARY_MAX_PROGRESS; + + if (absProgress < min) { + setAlpha(1f); + setContentAlpha(1); + setElevation(mMaxElevation); + } else if (absProgress < max) { + setAlpha(1f); + setContentAlpha(mapToRange(absProgress, min, max, 1f, 0f, LINEAR)); + setElevation(Utilities.mapToRange(absProgress, min, max, mMaxElevation, 0, LINEAR)); + } else { + setAlpha(mapToRange(absProgress, max, PRIMARY_GONE_PROGRESS, 1f, 0f, LINEAR)); + setContentAlpha(0f); + setElevation(0f); } + + setTranslationX(width * progress); } - public void setContentTranslation(float translation) { - mTextAndBackground.setTranslationX(translation); - mIconView.setTranslationX(translation); + /** + * Updates the alpha, content alpha, elevation, and clipping of this view. + * @param progress Range from [0, 1] or [-1, 0] + * When 0: Smallest clipping, zero alpha + * When 1/-1: Full clip, full alpha + */ + public void onSecondaryDrag(float progress) { + final float absProgress = Math.abs(progress); + + float min = SECONDARY_MIN_PROGRESS; + float max = SECONDARY_MAX_PROGRESS; + float contentMax = SECONDARY_CONTENT_MAX_PROGRESS; + + if (absProgress < min) { + setAlpha(0f); + setContentAlpha(0); + setElevation(0f); + } else if (absProgress < max) { + setAlpha(mapToRange(absProgress, min, max, 0, 1f, LINEAR)); + setContentAlpha(0f); + setElevation(0f); + } else { + setAlpha(1f); + setContentAlpha(absProgress > contentMax + ? 1f + : mapToRange(absProgress, max, contentMax, 0, 1f, LINEAR)); + setElevation(Utilities.mapToRange(absProgress, max, 1, 0, mMaxElevation, LINEAR)); + } + + final int width = getWidth(); + int crop = (int) (width * absProgress); + int space = (int) (absProgress > PRIMARY_GONE_PROGRESS + ? mapToRange(absProgress, PRIMARY_GONE_PROGRESS, 1f, mNotificationSpace, 0, LINEAR) + : mNotificationSpace); + if (progress < 0) { + mOutline.left = Math.max(0, getWidth() - crop + space); + mOutline.right = getWidth(); + } else { + mOutline.right = Math.min(getWidth(), crop - space); + mOutline.left = 0; + } + + float contentTransX = mMaxTransX * (1f - absProgress); + setContentTranslationX(progress < 0 + ? contentTransX + : -contentTransX); + invalidateOutline(); } - public NotificationInfo getNotificationInfo() { + public @Nullable NotificationInfo getNotificationInfo() { return mNotificationInfo; } - public boolean canChildBeDismissed() { return mNotificationInfo != null && mNotificationInfo.dismissable; } |