Update notification view to match newer specs

am: 7f3526a1a4

Change-Id: Icfd4edbd71808d00cdcc1885259ca540676fbfdc
This commit is contained in:
Tony Wickham
2017-02-24 20:59:47 +00:00
committed by android-build-merger
14 changed files with 270 additions and 164 deletions
-22
View File
@@ -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>
@@ -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>
+2 -19
View File
@@ -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"
+1 -1
View File
@@ -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"/>
+9 -8
View File
@@ -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>
+6 -7
View File
@@ -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>
@@ -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;
}
}
@@ -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));
}
}
@@ -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);
}
}
@@ -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);
@@ -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();
}
}
@@ -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) {
@@ -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) {
if (mIsAboveIcon) {
return ObjectAnimator.ofFloat(this, TRANSLATION_Y, getTranslationY() + translationY)
.setDuration(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);
}
return null;
if (mIsAboveIcon) {
// 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 animatorSet;
}
public Animator reduceNotificationViewHeight(int heightToRemove, int duration) {
return reduceNotificationViewHeight(heightToRemove, duration,
(NotificationItemView) findViewById(R.id.notification_view));
}
@Override
@@ -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();