diff options
author | Tony Wickham <twickham@google.com> | 2017-02-21 15:16:12 -0800 |
---|---|---|
committer | Tony Wickham <twickham@google.com> | 2017-02-24 12:09:06 -0800 |
commit | 7f3526a1a4d5d3578d4648abb1422646d23c6080 (patch) | |
tree | 92b451eba0558f192c84d4c982e9d754940e10ff | |
parent | e05b08f705e517be42da35a12508e54c05b1b5ff (diff) | |
download | android_packages_apps_Trebuchet-7f3526a1a4d5d3578d4648abb1422646d23c6080.tar.gz android_packages_apps_Trebuchet-7f3526a1a4d5d3578d4648abb1422646d23c6080.tar.bz2 android_packages_apps_Trebuchet-7f3526a1a4d5d3578d4648abb1422646d23c6080.zip |
Update notification view to match newer specs
- Use smaller radius for notifications round rect background
- Remove "Notifications" header, and clip children to round rect path
- Flip main notification so that icon shows on the right instead of
left; footer is also flipped so animation makes sense
- Clean up animations to animate view outline instead of height
Bug: 32410600
Change-Id: I6bd1e1f8395b3703f28c3b0056a89e67672368ab
-rw-r--r-- | res/drawable/bg_white_pill_bottom.xml | 22 | ||||
-rw-r--r-- | res/drawable/bg_white_round_rect.xml (renamed from res/drawable/bg_white_pill_top.xml) | 3 | ||||
-rw-r--r-- | res/layout/notification.xml | 21 | ||||
-rw-r--r-- | res/layout/notification_footer.xml | 2 | ||||
-rw-r--r-- | res/layout/notification_main.xml | 17 | ||||
-rw-r--r-- | res/values/dimens.xml | 13 | ||||
-rw-r--r-- | src/com/android/launcher3/LauncherAnimUtils.java | 13 | ||||
-rw-r--r-- | src/com/android/launcher3/anim/PillHeightRevealOutlineProvider.java | 43 | ||||
-rw-r--r-- | src/com/android/launcher3/anim/PropertyResetListener.java | 41 | ||||
-rw-r--r-- | src/com/android/launcher3/badge/BadgeRenderer.java | 1 | ||||
-rw-r--r-- | src/com/android/launcher3/notification/NotificationFooterLayout.java | 82 | ||||
-rw-r--r-- | src/com/android/launcher3/notification/NotificationItemView.java | 100 | ||||
-rw-r--r-- | src/com/android/launcher3/popup/PopupContainerWithArrow.java | 61 | ||||
-rw-r--r-- | src/com/android/launcher3/popup/PopupItemView.java | 13 |
14 files changed, 269 insertions, 163 deletions
diff --git a/res/drawable/bg_white_pill_bottom.xml b/res/drawable/bg_white_pill_bottom.xml deleted file mode 100644 index a1ea48cec..000000000 --- a/res/drawable/bg_white_pill_bottom.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2017 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. ---> - -<shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="rectangle"> - <solid android:color="#FFFFFF" /> - <corners android:bottomLeftRadius="@dimen/bg_pill_radius" - android:bottomRightRadius="@dimen/bg_pill_radius" /> -</shape>
\ No newline at end of file diff --git a/res/drawable/bg_white_pill_top.xml b/res/drawable/bg_white_round_rect.xml index 9988b2913..c7f786ff6 100644 --- a/res/drawable/bg_white_pill_top.xml +++ b/res/drawable/bg_white_round_rect.xml @@ -17,6 +17,5 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#FFFFFF" /> - <corners android:topLeftRadius="@dimen/bg_pill_radius" - android:topRightRadius="@dimen/bg_pill_radius" /> + <corners android:radius="@dimen/bg_round_rect_radius" /> </shape>
\ No newline at end of file diff --git a/res/layout/notification.xml b/res/layout/notification.xml index d828c4a36..48c7b48b9 100644 --- a/res/layout/notification.xml +++ b/res/layout/notification.xml @@ -20,7 +20,7 @@ android:layout_width="@dimen/bg_pill_width" android:layout_height="wrap_content" android:elevation="@dimen/deep_shortcuts_elevation" - android:background="@drawable/bg_white_pill"> + android:background="@drawable/bg_white_round_rect"> <RelativeLayout android:layout_width="match_parent" @@ -28,27 +28,10 @@ android:orientation="vertical" android:clipChildren="false"> - <TextView - android:id="@+id/header" - android:layout_width="match_parent" - android:layout_height="@dimen/notification_footer_collapsed_height" - android:gravity="center_vertical" - android:textAlignment="center" - android:text="@string/notifications_header" - android:elevation="@dimen/notification_elevation" - android:background="@drawable/bg_white_pill_top" /> - - <View - android:id="@+id/divider" - android:layout_width="match_parent" - android:layout_height="@dimen/notification_divider_height" - android:layout_below="@id/header" /> - <include layout="@layout/notification_main" android:id="@+id/main_view" android:layout_width="match_parent" - android:layout_height="@dimen/bg_pill_height" - android:layout_below="@id/divider" /> + android:layout_height="@dimen/notification_main_height" /> <include layout="@layout/notification_footer" android:id="@+id/footer" diff --git a/res/layout/notification_footer.xml b/res/layout/notification_footer.xml index ceea24a66..c025819a2 100644 --- a/res/layout/notification_footer.xml +++ b/res/layout/notification_footer.xml @@ -20,7 +20,6 @@ android:layout_height="match_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android" - android:background="@drawable/bg_white_pill_bottom" android:elevation="@dimen/notification_elevation" android:clipChildren="false" > @@ -34,6 +33,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" + android:gravity="end" android:padding="@dimen/notification_footer_icon_row_padding" android:clipToPadding="false" android:clipChildren="false"/> diff --git a/res/layout/notification_main.xml b/res/layout/notification_main.xml index 84827f114..d036fe5d2 100644 --- a/res/layout/notification_main.xml +++ b/res/layout/notification_main.xml @@ -21,20 +21,14 @@ android:layout_height="match_parent" android:orientation="horizontal" android:focusable="true" + android:padding="@dimen/notification_padding" android:elevation="@dimen/notification_elevation" > - <View - android:id="@+id/popup_item_icon" - android:layout_width="@dimen/notification_icon_size" - android:layout_height="@dimen/notification_icon_size" - android:layout_marginStart="@dimen/notification_icon_margin_start" - android:layout_gravity="center_vertical" /> - <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - android:layout_marginStart="@dimen/notification_text_margin_start" + android:layout_weight="1" android:gravity="center_vertical"> <TextView android:id="@+id/title" @@ -56,5 +50,12 @@ android:layout_height="wrap_content" /> </LinearLayout> + <View + android:id="@+id/popup_item_icon" + android:layout_width="@dimen/notification_icon_size" + android:layout_height="@dimen/notification_icon_size" + android:layout_weight="0" + android:layout_gravity="center_vertical" /> + </com.android.launcher3.notification.NotificationMainView> diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 517bf9f79..177e08e2f 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -175,19 +175,18 @@ <!-- Icon badges (with notification counts) --> <dimen name="badge_size">24dp</dimen> <dimen name="badge_text_size">12dp</dimen> - <dimen name="badge_small_padding">1dp</dimen> + <dimen name="badge_small_padding">0dp</dimen> <dimen name="badge_large_padding">3dp</dimen> <dimen name="notification_icon_size">28dp</dimen> <dimen name="notification_footer_icon_size">24dp</dimen> - <!-- (icon_size - secondary_icon_size) / 2 --> <!-- Notifications --> + <dimen name="bg_round_rect_radius">12dp</dimen> + <dimen name="notification_padding">12dp</dimen> + <!-- (icon_size - footer_icon_size) / 2 --> <dimen name="notification_footer_icon_row_padding">2dp</dimen> - <dimen name="notification_icon_margin_start">8dp</dimen> - <dimen name="notification_text_margin_start">8dp</dimen> - <dimen name="notification_footer_height">36dp</dimen> - <!-- The height to use when there are no icons in the footer --> - <dimen name="notification_footer_collapsed_height">@dimen/bg_pill_radius</dimen> + <dimen name="notification_main_height">60dp</dimen> + <dimen name="notification_footer_height">@dimen/bg_pill_height</dimen> <dimen name="notification_elevation">2dp</dimen> <dimen name="notification_divider_height">0.5dp</dimen> <dimen name="swipe_helper_falsing_threshold">70dp</dimen> diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java index 43cf827da..aa7f5ee5f 100644 --- a/src/com/android/launcher3/LauncherAnimUtils.java +++ b/src/com/android/launcher3/LauncherAnimUtils.java @@ -130,17 +130,4 @@ public class LauncherAnimUtils { return anim; } - public static ValueAnimator animateViewHeight(final View v, int fromHeight, int toHeight) { - ValueAnimator anim = ValueAnimator.ofInt(fromHeight, toHeight); - anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator valueAnimator) { - int val = (Integer) valueAnimator.getAnimatedValue(); - ViewGroup.LayoutParams layoutParams = v.getLayoutParams(); - layoutParams.height = val; - v.setLayoutParams(layoutParams); - } - }); - return anim; - } } diff --git a/src/com/android/launcher3/anim/PillHeightRevealOutlineProvider.java b/src/com/android/launcher3/anim/PillHeightRevealOutlineProvider.java new file mode 100644 index 000000000..be1e2d644 --- /dev/null +++ b/src/com/android/launcher3/anim/PillHeightRevealOutlineProvider.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2017 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.launcher3.anim; + +import android.graphics.Rect; + +import com.android.launcher3.util.PillRevealOutlineProvider; + +/** + * Extension of {@link PillRevealOutlineProvider} which only changes the height of the pill. + * For now, we assume the height is added/removed from the bottom. + */ +public class PillHeightRevealOutlineProvider extends PillRevealOutlineProvider { + + private final int mNewHeight; + + public PillHeightRevealOutlineProvider(Rect pillRect, float radius, int newHeight) { + super(0, 0, pillRect, radius); + mOutline.set(pillRect); + mNewHeight = newHeight; + } + + @Override + public void setProgress(float progress) { + mOutline.top = 0; + int heightDifference = mPillRect.height() - mNewHeight; + mOutline.bottom = (int) (mPillRect.bottom - heightDifference * (1 - progress)); + } +} diff --git a/src/com/android/launcher3/anim/PropertyResetListener.java b/src/com/android/launcher3/anim/PropertyResetListener.java new file mode 100644 index 000000000..eefb0148c --- /dev/null +++ b/src/com/android/launcher3/anim/PropertyResetListener.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2017 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.launcher3.anim; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.util.Property; + +/** + * An AnimatorListener that sets the given property to the given value at the end of the animation. + */ +public class PropertyResetListener<T, V> extends AnimatorListenerAdapter { + + private Property<T, V> mPropertyToReset; + private V mResetToValue; + + public PropertyResetListener(Property<T, V> propertyToReset, V resetToValue) { + mPropertyToReset = propertyToReset; + mResetToValue = resetToValue; + } + + @Override + public void onAnimationEnd(Animator animation) { + mPropertyToReset.set((T) ((ObjectAnimator) animation).getTarget(), mResetToValue); + } +} diff --git a/src/com/android/launcher3/badge/BadgeRenderer.java b/src/com/android/launcher3/badge/BadgeRenderer.java index 8bbc2afa2..864a65d8a 100644 --- a/src/com/android/launcher3/badge/BadgeRenderer.java +++ b/src/com/android/launcher3/badge/BadgeRenderer.java @@ -51,6 +51,7 @@ public class BadgeRenderer { mSmallIconDrawer = new IconDrawer(res.getDimensionPixelSize(R.dimen.badge_large_padding)); mTextPaint.setTextAlign(Paint.Align.CENTER); mTextPaint.setTextSize(res.getDimensionPixelSize(R.dimen.badge_text_size)); + mTextPaint.setFakeBoldText(true); // Measure the text height. Rect tempTextHeight = new Rect(); mTextPaint.getTextBounds("0", 0, 1, tempTextHeight); diff --git a/src/com/android/launcher3/notification/NotificationFooterLayout.java b/src/com/android/launcher3/notification/NotificationFooterLayout.java index 9686ae07d..62126ef83 100644 --- a/src/com/android/launcher3/notification/NotificationFooterLayout.java +++ b/src/com/android/launcher3/notification/NotificationFooterLayout.java @@ -21,18 +21,21 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; -import android.content.res.ColorStateList; import android.graphics.Rect; +import android.graphics.drawable.ColorDrawable; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; +import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.anim.PropertyListBuilder; +import com.android.launcher3.anim.PropertyResetListener; import com.android.launcher3.graphics.IconPalette; import com.android.launcher3.popup.PopupContainerWithArrow; @@ -50,16 +53,17 @@ public class NotificationFooterLayout extends LinearLayout { void onIconAnimationEnd(NotificationInfo animatedNotification); } - private static final int MAX_FOOTER_NOTIFICATIONS = 5; + private static final int MAX_FOOTER_NOTIFICATIONS = 4; private static final Rect sTempRect = new Rect(); private final List<NotificationInfo> mNotifications = new ArrayList<>(); private final List<NotificationInfo> mOverflowNotifications = new ArrayList<>(); + private final boolean mRtl; LinearLayout.LayoutParams mIconLayoutParams; private LinearLayout mIconRow; - private int mBackgroundColor; + private final ColorDrawable mBackgroundColor; private int mTextColor; private TextView mOverflowView; @@ -74,13 +78,17 @@ public class NotificationFooterLayout extends LinearLayout { public NotificationFooterLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + mRtl = Utilities.isRtl(getResources()); + int size = getResources().getDimensionPixelSize( R.dimen.notification_footer_icon_size); - int padding = getResources().getDimensionPixelSize( - R.dimen.deep_shortcut_drawable_padding); + int padding = getResources().getDimensionPixelSize(R.dimen.notification_padding); mIconLayoutParams = new LayoutParams(size, size); - mIconLayoutParams.setMarginStart(padding); + mIconLayoutParams.setMarginEnd(padding); mIconLayoutParams.gravity = Gravity.CENTER_VERTICAL; + + mBackgroundColor = new ColorDrawable(); + setBackground(mBackgroundColor); } @Override @@ -90,12 +98,15 @@ public class NotificationFooterLayout extends LinearLayout { } public void applyColors(IconPalette iconPalette) { - mBackgroundColor = iconPalette.backgroundColor; - setBackgroundTintList(ColorStateList.valueOf(mBackgroundColor)); + mBackgroundColor.setColor(iconPalette.backgroundColor); findViewById(R.id.divider).setBackgroundColor(iconPalette.secondaryColor); mTextColor = iconPalette.textColor; } + public int getBackgroundColor() { + return mBackgroundColor.getColor(); + } + /** * Keep track of the NotificationInfo, and then update the UI when * {@link #commitNotificationInfos()} is called. @@ -124,18 +135,18 @@ public class NotificationFooterLayout extends LinearLayout { mOverflowView = new TextView(getContext()); mOverflowView.setTextColor(mTextColor); updateOverflowText(); - mIconRow.addView(mOverflowView, mIconLayoutParams); + mIconRow.addView(mOverflowView, 0, mIconLayoutParams); } } private void addNotificationIconForInfo(NotificationInfo info, boolean fromOverflow) { View icon = new View(getContext()); - icon.setBackground(info.getIconForBackground(getContext(), mBackgroundColor)); + icon.setBackground(info.getIconForBackground(getContext(), getBackgroundColor())); icon.setOnClickListener(info); - int addIndex = mIconRow.getChildCount(); + int addIndex = 0; if (fromOverflow) { // Add the notification before the overflow view. - addIndex--; + addIndex = 1; icon.setAlpha(0); icon.animate().alpha(1); } @@ -151,7 +162,7 @@ public class NotificationFooterLayout extends LinearLayout { public void animateFirstNotificationTo(Rect toBounds, final IconAnimationEndListener callback) { AnimatorSet animation = LauncherAnimUtils.createAnimatorSet(); - final View firstNotification = mIconRow.getChildAt(0); + final View firstNotification = mIconRow.getChildAt(mIconRow.getChildCount() - 1); Rect fromBounds = sTempRect; firstNotification.getGlobalVisibleRect(fromBounds); @@ -169,20 +180,19 @@ public class NotificationFooterLayout extends LinearLayout { animation.play(moveAndScaleIcon); // Shift all notifications (not the overflow) over to fill the gap. - int gapWidth = mIconLayoutParams.width + mIconLayoutParams.getMarginStart(); - int numIcons = mIconRow.getChildCount() - - (mOverflowNotifications.isEmpty() ? 0 : 1); - for (int i = 1; i < numIcons; i++) { + int gapWidth = mIconLayoutParams.width + mIconLayoutParams.getMarginEnd(); + if (mRtl) { + gapWidth = -gapWidth; + } + int numIcons = mIconRow.getChildCount() - 1; + // We have to set the translation X to 0 when the new main notification + // is removed from the footer. + PropertyResetListener<View, Float> propertyResetListener + = new PropertyResetListener<>(TRANSLATION_X, 0f); + for (int i = mOverflowNotifications.isEmpty() ? 0 : 1; i < numIcons; i++) { final View child = mIconRow.getChildAt(i); - Animator shiftChild = ObjectAnimator.ofFloat(child, TRANSLATION_X, -gapWidth); - shiftChild.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - // We have to set the translation X to 0 when the new main notification - // is removed from the footer. - child.setTranslationX(0); - } - }); + Animator shiftChild = ObjectAnimator.ofFloat(child, TRANSLATION_X, gapWidth); + shiftChild.addListener(propertyResetListener); animation.play(shiftChild); } animation.start(); @@ -205,18 +215,18 @@ public class NotificationFooterLayout extends LinearLayout { } } if (mIconRow.getChildCount() == 0) { - // There are no more icons in the secondary view, so hide it. + // There are no more icons in the footer, so hide it. PopupContainerWithArrow popup = PopupContainerWithArrow.getOpen( Launcher.getLauncher(getContext())); - int newHeight = getResources().getDimensionPixelSize( - R.dimen.notification_footer_collapsed_height); - AnimatorSet collapseSecondary = LauncherAnimUtils.createAnimatorSet(); - collapseSecondary.play(popup.animateTranslationYBy(getHeight() - newHeight, 0)); - collapseSecondary.play(LauncherAnimUtils.animateViewHeight( - this, getHeight(), newHeight)); - collapseSecondary.setDuration(getResources().getInteger( - R.integer.config_removeNotificationViewDuration)); - collapseSecondary.start(); + Animator collapseFooter = popup.reduceNotificationViewHeight(getHeight(), + getResources().getInteger(R.integer.config_removeNotificationViewDuration)); + collapseFooter.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + ((ViewGroup) getParent()).removeView(NotificationFooterLayout.this); + } + }); + collapseFooter.start(); } } diff --git a/src/com/android/launcher3/notification/NotificationItemView.java b/src/com/android/launcher3/notification/NotificationItemView.java index d58bef697..742c90a5a 100644 --- a/src/com/android/launcher3/notification/NotificationItemView.java +++ b/src/com/android/launcher3/notification/NotificationItemView.java @@ -18,29 +18,32 @@ package com.android.launcher3.notification; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; import android.content.Context; import android.content.res.ColorStateList; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; import android.graphics.Rect; +import android.graphics.Shader; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; -import android.view.animation.LinearInterpolator; +import android.view.ViewGroup; import android.widget.FrameLayout; -import android.widget.TextView; import com.android.launcher3.ItemInfo; -import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.R; import com.android.launcher3.graphics.IconPalette; import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider; import com.android.launcher3.popup.PopupItemView; import com.android.launcher3.userevent.nano.LauncherLogProto; +import com.android.launcher3.anim.PillHeightRevealOutlineProvider; import java.util.List; -import static com.android.launcher3.LauncherAnimUtils.animateViewHeight; - /** * A {@link FrameLayout} that contains a header, main view and a footer. * The main view contains the icon and text (title + subtext) of the first notification. @@ -51,7 +54,9 @@ public class NotificationItemView extends PopupItemView implements LogContainerP private static final Rect sTempRect = new Rect(); - private TextView mHeader; + private final Paint mBackgroundClipPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | + Paint.FILTER_BITMAP_FLAG); + private View mDivider; private NotificationMainView mMainView; private NotificationFooterLayout mFooter; @@ -73,11 +78,65 @@ public class NotificationItemView extends PopupItemView implements LogContainerP @Override protected void onFinishInflate() { super.onFinishInflate(); - mHeader = (TextView) findViewById(R.id.header); mDivider = findViewById(R.id.divider); mMainView = (NotificationMainView) findViewById(R.id.main_view); mFooter = (NotificationFooterLayout) findViewById(R.id.footer); mSwipeHelper = new SwipeHelper(SwipeHelper.X, mMainView, getContext()); + mSwipeHelper.setDisableHardwareLayers(true); + } + + private void initializeBackgroundClipping(boolean force) { + if (force || mBackgroundClipPaint.getShader() == null) { + mBackgroundClipPaint.setXfermode(null); + mBackgroundClipPaint.setShader(null); + Bitmap backgroundBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), + Bitmap.Config.ALPHA_8); + Canvas canvas = new Canvas(); + canvas.setBitmap(backgroundBitmap); + float roundRectRadius = getResources().getDimensionPixelSize( + R.dimen.bg_round_rect_radius); + canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), + roundRectRadius, roundRectRadius, mBackgroundClipPaint); + Shader backgroundClipShader = new BitmapShader(backgroundBitmap, + Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + mBackgroundClipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); + mBackgroundClipPaint.setShader(backgroundClipShader); + } + } + + @Override + protected void dispatchDraw(Canvas canvas) { + initializeBackgroundClipping(false /* force */); + int saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, + Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); + super.dispatchDraw(canvas); + canvas.drawPaint(mBackgroundClipPaint); + canvas.restoreToCount(saveCount); + } + + public Animator animateHeightRemoval(int heightToRemove) { + final int newHeight = getHeight() - heightToRemove; + Animator heightAnimator = new PillHeightRevealOutlineProvider(mPillRect, + getBackgroundRadius(), newHeight).createRevealAnimator(this, true /* isReversed */); + heightAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (newHeight > 0) { + measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY)); + initializeBackgroundClipping(true /* force */); + invalidate(); + } else { + ((ViewGroup) getParent()).removeView(NotificationItemView.this); + } + } + }); + return heightAnimator; + } + + @Override + protected float getBackgroundRadius() { + return getResources().getDimensionPixelSize(R.dimen.bg_round_rect_radius); } @Override @@ -103,7 +162,7 @@ public class NotificationItemView extends PopupItemView implements LogContainerP protected ColorStateList getAttachedArrowColor() { // This NotificationView itself has a different color that is only // revealed when dismissing notifications. - return mFooter.getBackgroundTintList(); + return ColorStateList.valueOf(mFooter.getBackgroundColor()); } public void applyNotificationInfos(final List<NotificationInfo> notificationInfos) { @@ -122,8 +181,6 @@ public class NotificationItemView extends PopupItemView implements LogContainerP public void applyColors(IconPalette iconPalette) { setBackgroundTintList(ColorStateList.valueOf(iconPalette.secondaryColor)); - mHeader.setBackgroundTintList(ColorStateList.valueOf(iconPalette.backgroundColor)); - mHeader.setTextColor(ColorStateList.valueOf(iconPalette.textColor)); mDivider.setBackgroundColor(iconPalette.secondaryColor); mMainView.applyColors(iconPalette); mFooter.applyColors(iconPalette); @@ -154,27 +211,6 @@ public class NotificationItemView extends PopupItemView implements LogContainerP } } - public Animator createRemovalAnimation(int fullDuration) { - AnimatorSet animation = new AnimatorSet(); - int mainHeight = mMainView.getMeasuredHeight(); - Animator removeMainView = animateViewHeight(mMainView, mainHeight, 0); - removeMainView.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - // Remove the remaining views but take on their color instead of the darker one. - setBackgroundTintList(mHeader.getBackgroundTintList()); - removeAllViews(); - } - }); - Animator removeRest = LauncherAnimUtils.animateViewHeight(this, getHeight() - mainHeight, 0); - removeMainView.setDuration(fullDuration / 2); - removeRest.setDuration(fullDuration / 2); - removeMainView.setInterpolator(new LinearInterpolator()); - removeRest.setInterpolator(new LinearInterpolator()); - animation.playSequentially(removeMainView, removeRest); - return animation; - } - @Override public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target, LauncherLogProto.Target targetParent) { diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index d34727c8d..7811b960e 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -34,7 +34,6 @@ import android.graphics.drawable.ShapeDrawable; import android.os.Build; import android.os.Handler; import android.os.Looper; -import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.Gravity; import android.view.LayoutInflater; @@ -60,6 +59,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.accessibility.ShortcutMenuAccessibilityDelegate; import com.android.launcher3.anim.PropertyListBuilder; +import com.android.launcher3.anim.PropertyResetListener; import com.android.launcher3.badge.BadgeInfo; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragLayer; @@ -225,7 +225,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView } private void addDummyViews(BubbleTextView originalIcon, - PopupPopulator.Item[] itemsToPopulate, boolean secondaryNotificationViewHasIcons) { + PopupPopulator.Item[] itemsToPopulate, boolean notificationFooterHasIcons) { final Resources res = getResources(); final int spacing = res.getDimensionPixelSize(R.dimen.deep_shortcuts_spacing); final LayoutInflater inflater = mLauncher.getLayoutInflater(); @@ -234,10 +234,9 @@ public class PopupContainerWithArrow extends AbstractFloatingView final PopupItemView item = (PopupItemView) inflater.inflate( itemsToPopulate[i].layoutId, this, false); if (itemsToPopulate[i] == PopupPopulator.Item.NOTIFICATION) { - int secondaryHeight = secondaryNotificationViewHasIcons ? - res.getDimensionPixelSize(R.dimen.notification_footer_height) : - res.getDimensionPixelSize(R.dimen.notification_footer_collapsed_height); - item.findViewById(R.id.footer).getLayoutParams().height = secondaryHeight; + int footerHeight = notificationFooterHasIcons ? + res.getDimensionPixelSize(R.dimen.notification_footer_height) : 0; + item.findViewById(R.id.footer).getLayoutParams().height = footerHeight; } if (i < numItems - 1) { ((LayoutParams) item.getLayoutParams()).bottomMargin = spacing; @@ -575,7 +574,8 @@ public class PopupContainerWithArrow extends AbstractFloatingView } public void trimNotifications(Map<PackageUserKey, BadgeInfo> updatedBadges) { - final NotificationItemView notificationView = (NotificationItemView) findViewById(R.id.notification_view); + final NotificationItemView notificationView = + (NotificationItemView) findViewById(R.id.notification_view); if (notificationView == null) { return; } @@ -586,9 +586,8 @@ public class PopupContainerWithArrow extends AbstractFloatingView final int duration = getResources().getInteger( R.integer.config_removeNotificationViewDuration); final int spacing = getResources().getDimensionPixelSize(R.dimen.deep_shortcuts_spacing); - removeNotification.play(animateTranslationYBy(notificationView.getHeight() + spacing, - duration)); - Animator reduceHeight = notificationView.createRemovalAnimation(duration); + removeNotification.play(reduceNotificationViewHeight( + notificationView.getHeight() + spacing, duration, notificationView)); final View removeMarginView = mIsAboveIcon ? getItemViewAt(getItemCount() - 2) : notificationView; if (removeMarginView != null) { @@ -602,7 +601,6 @@ public class PopupContainerWithArrow extends AbstractFloatingView }); removeNotification.play(removeMargin); } - removeNotification.play(reduceHeight); Animator fade = ObjectAnimator.ofFloat(notificationView, ALPHA, 0) .setDuration(duration); fade.addListener(new AnimatorListenerAdapter() { @@ -636,16 +634,43 @@ public class PopupContainerWithArrow extends AbstractFloatingView mArrow, new PropertyListBuilder().scale(scale).build()); } /** - * Animates the translationY of this container if it is open above the icon. - * If it is below the icon, the container already shifts up when the height - * of a child (e.g. NotificationView) changes, so the translation isn't necessary. + * Animates the height of the notification item and the translationY of other items accordingly. */ - public @Nullable Animator animateTranslationYBy(int translationY, int duration) { + public Animator reduceNotificationViewHeight(int heightToRemove, int duration, + NotificationItemView notificationItem) { + final int translateYBy = mIsAboveIcon ? heightToRemove : -heightToRemove; + AnimatorSet animatorSet = LauncherAnimUtils.createAnimatorSet(); + animatorSet.play(notificationItem.animateHeightRemoval(heightToRemove)); + PropertyResetListener<View, Float> resetTranslationYListener + = new PropertyResetListener<>(TRANSLATION_Y, 0f); + for (int i = 0; i < getItemCount(); i++) { + final PopupItemView itemView = getItemViewAt(i); + if (!mIsAboveIcon && itemView == notificationItem) { + // The notification view is already in the right place when container is below icon. + continue; + } + ValueAnimator translateItem = ObjectAnimator.ofFloat(itemView, TRANSLATION_Y, + itemView.getTranslationY() + translateYBy).setDuration(duration); + translateItem.addListener(resetTranslationYListener); + animatorSet.play(translateItem); + } if (mIsAboveIcon) { - return ObjectAnimator.ofFloat(this, TRANSLATION_Y, getTranslationY() + translationY) - .setDuration(duration); + // All the items, including the notification item, translated down, but the + // container itself did not. This means the items would jump back to their + // original translation unless we update the container's translationY here. + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + setTranslationY(getTranslationY() + translateYBy); + } + }); } - return null; + return animatorSet; + } + + public Animator reduceNotificationViewHeight(int heightToRemove, int duration) { + return reduceNotificationViewHeight(heightToRemove, duration, + (NotificationItemView) findViewById(R.id.notification_view)); } @Override diff --git a/src/com/android/launcher3/popup/PopupItemView.java b/src/com/android/launcher3/popup/PopupItemView.java index 6af6e7d2c..b3d7155aa 100644 --- a/src/com/android/launcher3/popup/PopupItemView.java +++ b/src/com/android/launcher3/popup/PopupItemView.java @@ -42,7 +42,7 @@ public abstract class PopupItemView extends FrameLayout protected static final Point sTempPoint = new Point(); - private final Rect mPillRect; + protected final Rect mPillRect; private float mOpenAnimationProgress; protected View mIconView; @@ -147,6 +147,10 @@ public abstract class PopupItemView extends FrameLayout return sTempPoint; } + protected float getBackgroundRadius() { + return getResources().getDimensionPixelSize(R.dimen.bg_pill_radius); + } + /** * Extension of {@link PillRevealOutlineProvider} which scales the icon based on the height. */ @@ -161,10 +165,9 @@ public abstract class PopupItemView extends FrameLayout private final boolean mPivotLeft; private final float mTranslateX; - public ZoomRevealOutlineProvider(int x, int y, Rect pillRect, - View translateView, View zoomView, boolean isContainerAboveIcon, boolean pivotLeft) { - super(x, y, pillRect, zoomView.getResources().getDimensionPixelSize( - R.dimen.bg_pill_radius)); + public ZoomRevealOutlineProvider(int x, int y, Rect pillRect, PopupItemView translateView, + View zoomView, boolean isContainerAboveIcon, boolean pivotLeft) { + super(x, y, pillRect, translateView.getBackgroundRadius()); mTranslateView = translateView; mZoomView = zoomView; mFullHeight = pillRect.height(); |