summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Selim Cinek <cinek@google.com> 2016-11-04 14:55:30 -0700
committer Selim Cinek <cinek@google.com> 2016-11-28 13:44:34 -0800
commit49014f85220eb064f7cb9326ab84117c53c8e43b (patch)
treef312c87c9578a85b5a210129a108fa3b4a06e219
parentc40c79ac66d8162880e0ef76c98f44bc40797bbd (diff)
Implemented a nicer transition when the icons overflow
The overflowing icons are now represented as dots and animate in and out nicer. The shelf also animates much nicer from the regular statusbar size if there are a lot of notifications. Test: Add a lot of notifications, observe them nicely overflowing into dots Bug: 32437839 Change-Id: I5906c076bbf5d48cbabdbacfd21234bed55c6caa
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_shelf.xml4
-rw-r--r--packages/SystemUI/res/values/dimens.xml6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java85
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java160
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java152
6 files changed, 366 insertions, 56 deletions
diff --git a/packages/SystemUI/res/layout/status_bar_notification_shelf.xml b/packages/SystemUI/res/layout/status_bar_notification_shelf.xml
index fde61ebc77b9..088deba807f5 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_shelf.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_shelf.xml
@@ -35,8 +35,8 @@
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginStart="13dp"
- android:layout_marginEnd="13dp"
+ android:paddingStart="13dp"
+ android:paddingEnd="13dp"
android:gravity="center_vertical" />
<com.android.systemui.statusbar.notification.FakeShadowView
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 496fb9c9f6c4..11d42b314a43 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -112,6 +112,12 @@
<!-- the padding on the start of the statusbar -->
<dimen name="status_bar_padding_start">6dp</dimen>
+ <!-- the radius of the overflow dot in the status bar -->
+ <dimen name="overflow_dot_radius">1dp</dimen>
+
+ <!-- the padding between dots in the icon overflow -->
+ <dimen name="overflow_icon_dot_padding">3dp</dimen>
+
<!-- The padding on the global screenshot background image -->
<dimen name="global_screenshot_bg_padding">20dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 9a1e0649c805..de88e6650245 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -48,7 +48,7 @@ public class NotificationShelf extends ActivatableNotificationView {
private ViewInvertHelper mViewInvertHelper;
private boolean mDark;
- private NotificationIconContainer mNotificationIconContainer;
+ private NotificationIconContainer mShelfIcons;
private ArrayList<StatusBarIconView> mIcons = new ArrayList<>();
private ShelfState mShelfState;
private int[] mTmp = new int[2];
@@ -62,6 +62,7 @@ public class NotificationShelf extends ActivatableNotificationView {
private int mPaddingBetweenElements;
private int mNotGoneIndex;
private boolean mHasItemsInStableShelf;
+ private NotificationIconContainer mCollapsedIcons;
public NotificationShelf(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -70,14 +71,15 @@ public class NotificationShelf extends ActivatableNotificationView {
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mNotificationIconContainer = (NotificationIconContainer) findViewById(R.id.content);
- mNotificationIconContainer.setClipChildren(false);
- mNotificationIconContainer.setClipToPadding(false);
+ mShelfIcons = (NotificationIconContainer) findViewById(R.id.content);
+ mShelfIcons.setClipChildren(false);
+ mShelfIcons.setClipToPadding(false);
+
setClipToActualHeight(false);
setClipChildren(false);
setClipToPadding(false);
- mNotificationIconContainer.setShowAllIcons(false);
- mViewInvertHelper = new ViewInvertHelper(mNotificationIconContainer,
+ mShelfIcons.setShowAllIcons(false);
+ mViewInvertHelper = new ViewInvertHelper(mShelfIcons,
NotificationPanelView.DOZE_ANIMATION_DURATION);
mShelfState = new ShelfState();
initDimens();
@@ -118,11 +120,11 @@ public class NotificationShelf extends ActivatableNotificationView {
@Override
protected View getContentView() {
- return mNotificationIconContainer;
+ return mShelfIcons;
}
- public NotificationIconContainer getNotificationIconContainer() {
- return mNotificationIconContainer;
+ public NotificationIconContainer getShelfIcons() {
+ return mShelfIcons;
}
@Override
@@ -142,13 +144,13 @@ public class NotificationShelf extends ActivatableNotificationView {
float viewEnd = lastViewState.yTranslation + lastViewState.height;
mShelfState.copyFrom(lastViewState);
mShelfState.height = getIntrinsicHeight();
- mShelfState.yTranslation = Math.min(viewEnd, maxShelfEnd) - mShelfState.height;
+ mShelfState.yTranslation = Math.max(Math.min(viewEnd, maxShelfEnd) - mShelfState.height,
+ getFullyClosedTranslation());
mShelfState.zTranslation = ambientState.getBaseZHeight();
float openedAmount = (mShelfState.yTranslation - getFullyClosedTranslation())
/ (getIntrinsicHeight() * 2);
openedAmount = Math.min(1.0f, openedAmount);
- mShelfState.iconContainerTranslation = (1.0f - openedAmount)
- * (mStatusBarPaddingStart - mNotificationIconContainer.getLeft());
+ mShelfState.openedAmount = openedAmount;
mShelfState.clipTopAmount = 0;
mShelfState.alpha = 1.0f;
mShelfState.belowShelf = false;
@@ -172,10 +174,16 @@ public class NotificationShelf extends ActivatableNotificationView {
*/
public void updateAppearance() {
WeakHashMap<View, IconState> iconStates =
- mNotificationIconContainer.resetViewStates();
+ mShelfIcons.resetViewStates();
float numIconsInShelf = 0.0f;
int shelfIndex = mAmbientState.getShelfIndex();
mNotGoneIndex = -1;
+ float interpolationStart = mMaxLayoutHeight - getIntrinsicHeight() * 2;
+ float expandAmount = 0.0f;
+ if (getTranslationY() >= interpolationStart) {
+ expandAmount = (getTranslationY() - interpolationStart) / getIntrinsicHeight();
+ expandAmount = Math.min(1.0f, expandAmount);
+ }
// find the first view that doesn't overlap with the shelf
int notificationIndex = 0;
int notGoneNotifications = 0;
@@ -205,7 +213,7 @@ public class NotificationShelf extends ActivatableNotificationView {
}
}
updateNotificationClipHeight(row, notificationClipEnd);
- updateIconAppearance(row, iconState, icon);
+ updateIconAppearance(row, iconState, icon, expandAmount);
numIconsInShelf += iconState.iconAppearAmount;
if (row.getTranslationY() >= getTranslationY() && mNotGoneIndex == -1) {
mNotGoneIndex = notGoneNotifications;
@@ -228,8 +236,8 @@ public class NotificationShelf extends ActivatableNotificationView {
}
notificationIndex++;
}
- mNotificationIconContainer.calculateIconTranslations();
- mNotificationIconContainer.applyIconStates();
+ mShelfIcons.calculateIconTranslations();
+ mShelfIcons.applyIconStates();
setVisibility(numIconsInShelf == 0.0f || !mAmbientState.isShadeExpanded() ? INVISIBLE
: VISIBLE);
setHideBackground(numIconsInShelf < 1.0f);
@@ -247,8 +255,8 @@ public class NotificationShelf extends ActivatableNotificationView {
}
}
- private void updateIconAppearance(ExpandableNotificationRow row,
- IconState iconState, StatusBarIconView icon) {
+ private void updateIconAppearance(ExpandableNotificationRow row, IconState iconState,
+ StatusBarIconView icon, float expandAmount) {
// Let calculate how much the view is in the shelf
float viewStart = row.getTranslationY();
int transformHeight = row.getActualHeight() + mPaddingBetweenElements;
@@ -259,12 +267,6 @@ public class NotificationShelf extends ActivatableNotificationView {
float linearAmount = (getTranslationY() - viewStart) / transformHeight;
float interpolatedAmount = Interpolators.ACCELERATE_DECELERATE.getInterpolation(
linearAmount);
- float interpolationStart = mMaxLayoutHeight - getIntrinsicHeight() * 2;
- float expandAmount = 0.0f;
- if (getTranslationY() >= interpolationStart) {
- expandAmount = (getTranslationY() - interpolationStart) / getIntrinsicHeight();
- expandAmount = Math.min(1.0f, expandAmount);
- }
interpolatedAmount = NotificationUtils.interpolate(
interpolatedAmount, linearAmount, expandAmount);
iconState.iconAppearAmount = 1.0f - interpolatedAmount;
@@ -318,7 +320,7 @@ public class NotificationShelf extends ActivatableNotificationView {
// The notification size is different from the size in the shelf / statusbar
float newSize = NotificationUtils.interpolate(notificationIconSize, shelfIconSize,
transitionAmount);
- iconState.scaleX = newSize / icon.getHeight();
+ iconState.scaleX = newSize / icon.getHeight() / icon.getIconScale();
iconState.scaleY = iconState.scaleX;
iconState.hidden = transitionAmount == 0.0f;
row.setIconTransformationAmount(transitionAmount);
@@ -326,8 +328,8 @@ public class NotificationShelf extends ActivatableNotificationView {
if (row.isInShelf() && !row.isTransformingIntoShelf()) {
iconState.iconAppearAmount = 1.0f;
iconState.alpha = 1.0f;
- iconState.scaleX = shelfIconSize / icon.getHeight();
- iconState.scaleY = iconState.scaleX;
+ iconState.scaleX = 1.0f;
+ iconState.scaleY = 1.0f;
iconState.hidden = false;
}
}
@@ -378,8 +380,23 @@ public class NotificationShelf extends ActivatableNotificationView {
return super.shouldHideBackground() || mHideBackground;
}
- private void setIconContainerTranslation(float iconContainerTranslation) {
- mNotificationIconContainer.setTranslationX(iconContainerTranslation);
+ private void setOpenedAmount(float openedAmount) {
+ mCollapsedIcons.getLocationOnScreen(mTmp);
+ int start = mTmp[0];
+ if (isLayoutRtl()) {
+ start = getWidth() - start - mCollapsedIcons.getWidth();
+ }
+ int width = (int) NotificationUtils.interpolate(start + mCollapsedIcons.getWidth(),
+ mShelfIcons.getWidth(),
+ openedAmount);
+ mShelfIcons.setActualLayoutWidth(width);
+ float padding = NotificationUtils.interpolate(mCollapsedIcons.getPaddingEnd(),
+ mShelfIcons.getPaddingEnd(),
+ openedAmount);
+ mShelfIcons.setActualPaddingEnd(padding);
+ float paddingStart = NotificationUtils.interpolate(start,
+ mShelfIcons.getPaddingStart(), openedAmount);
+ mShelfIcons.setActualPaddingStart(paddingStart);
}
public void setMaxLayoutHeight(int maxLayoutHeight) {
@@ -405,23 +422,27 @@ public class NotificationShelf extends ActivatableNotificationView {
return mHasItemsInStableShelf;
}
+ public void setCollapsedIcons(NotificationIconContainer collapsedIcons) {
+ mCollapsedIcons = collapsedIcons;
+ }
+
private class ShelfState extends ExpandableViewState {
- private float iconContainerTranslation;
+ private float openedAmount;
private boolean hasItemsInStableShelf;
@Override
public void applyToView(View view) {
super.applyToView(view);
updateAppearance();
- setIconContainerTranslation(iconContainerTranslation);
+ setOpenedAmount(openedAmount);
setHasItemsInStableShelf(hasItemsInStableShelf);
}
@Override
public void animateTo(View child, AnimationProperties properties) {
super.animateTo(child, properties);
+ setOpenedAmount(openedAmount);
updateAppearance();
- setIconContainerTranslation(iconContainerTranslation);
setHasItemsInStableShelf(hasItemsInStableShelf);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 03e366283b4e..543f899283d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -16,6 +16,10 @@
package com.android.systemui.statusbar;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.app.Notification;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -30,20 +34,55 @@ import android.os.Parcelable;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.FloatProperty;
import android.util.Log;
+import android.util.Property;
import android.util.TypedValue;
import android.view.ViewDebug;
import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.Interpolator;
import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.NotificationUtils;
import java.text.NumberFormat;
public class StatusBarIconView extends AnimatedImageView {
+ public static final int STATE_ICON = 0;
+ public static final int STATE_DOT = 1;
+ public static final int STATE_HIDDEN = 2;
+
private static final String TAG = "StatusBarIconView";
- private boolean mAlwaysScaleIcon;
+ private static final Property<StatusBarIconView, Float> ICON_APPEAR_AMOUNT
+ = new FloatProperty<StatusBarIconView>("iconAppearAmount") {
+
+ @Override
+ public void setValue(StatusBarIconView object, float value) {
+ object.setIconAppearAmount(value);
+ }
+
+ @Override
+ public Float get(StatusBarIconView object) {
+ return object.getIconAppearAmount();
+ }
+ };
+ private static final Property<StatusBarIconView, Float> DOT_APPEAR_AMOUNG
+ = new FloatProperty<StatusBarIconView>("dot_appear_amount") {
+ @Override
+ public void setValue(StatusBarIconView object, float value) {
+ object.setDotAppearAmount(value);
+ }
+
+ @Override
+ public Float get(StatusBarIconView object) {
+ return object.getDotAppearAmount();
+ }
+ };
+
+ private boolean mAlwaysScaleIcon;
private StatusBarIcon mIcon;
@ViewDebug.ExportedProperty private String mSlot;
private Drawable mNumberBackground;
@@ -55,6 +94,15 @@ public class StatusBarIconView extends AnimatedImageView {
private final boolean mBlocked;
private int mDensity;
private float mIconScale = 1.0f;
+ private final Paint mDotPaint = new Paint();
+ private boolean mDotVisible;
+ private float mDotRadius;
+ private int mStaticDotRadius;
+ private int mVisibleState = STATE_ICON;
+ private float mIconAppearAmount = 1.0f;
+ private ObjectAnimator mIconAppearAnimator;
+ private ObjectAnimator mDotAnimator;
+ private float mDotAppearAmount;
public StatusBarIconView(Context context, String slot, Notification notification) {
this(context, slot, notification, false);
@@ -73,6 +121,11 @@ public class StatusBarIconView extends AnimatedImageView {
maybeUpdateIconScale();
setScaleType(ScaleType.CENTER);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
+ if (mNotification != null) {
+ setIconTint(getContext().getColor(
+ com.android.internal.R.color.notification_icon_default_color));
+ }
+ reloadDimens();
}
private void maybeUpdateIconScale() {
@@ -88,8 +141,6 @@ public class StatusBarIconView extends AnimatedImageView {
final int outerBounds = res.getDimensionPixelSize(R.dimen.status_bar_icon_size);
final int imageBounds = res.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size);
mIconScale = (float)imageBounds / (float)outerBounds;
- setScaleX(mIconScale);
- setScaleY(mIconScale);
}
public float getIconScale() {
@@ -104,6 +155,15 @@ public class StatusBarIconView extends AnimatedImageView {
mDensity = density;
maybeUpdateIconScale();
updateDrawable();
+ reloadDimens();
+ }
+ }
+
+ private void reloadDimens() {
+ boolean applyRadius = mDotRadius == mStaticDotRadius;
+ mStaticDotRadius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius);
+ if (applyRadius) {
+ mDotRadius = mStaticDotRadius;
}
}
@@ -264,12 +324,32 @@ public class StatusBarIconView extends AnimatedImageView {
@Override
protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
+ if (mIconAppearAmount > 0.0f) {
+ canvas.save();
+ canvas.scale(mIconScale * mIconAppearAmount, mIconScale * mIconAppearAmount,
+ getWidth() / 2, getHeight() / 2);
+ super.onDraw(canvas);
+ canvas.restore();
+ }
if (mNumberBackground != null) {
mNumberBackground.draw(canvas);
canvas.drawText(mNumberText, mNumberX, mNumberY, mNumberPain);
}
+ if (mDotAppearAmount != 0.0f) {
+ float radius;
+ float alpha;
+ if (mDotAppearAmount <= 1.0f) {
+ radius = mDotRadius * mDotAppearAmount;
+ alpha = 1.0f;
+ } else {
+ float fadeOutAmount = mDotAppearAmount - 1.0f;
+ alpha = 1.0f - fadeOutAmount;
+ radius = NotificationUtils.interpolate(mDotRadius, getWidth() / 4, fadeOutAmount);
+ }
+ mDotPaint.setAlpha((int) (alpha * 255));
+ canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, mDotPaint);
+ }
}
@Override
@@ -356,4 +436,76 @@ public class StatusBarIconView extends AnimatedImageView {
return c.getString(R.string.accessibility_desc_notification_icon, appName, desc);
}
+ public void setIconTint(int iconTint) {
+ mDotPaint.setColor(iconTint);
+ }
+
+ public void setVisibleState(int visibleState) {
+ if (visibleState != mVisibleState) {
+ mVisibleState = visibleState;
+ if (mIconAppearAnimator != null) {
+ mIconAppearAnimator.cancel();
+ }
+ float targetAmount = 0.0f;
+ Interpolator interpolator = Interpolators.FAST_OUT_LINEAR_IN;
+ if (visibleState == STATE_ICON) {
+ targetAmount = 1.0f;
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN;
+ }
+ mIconAppearAnimator = ObjectAnimator.ofFloat(this, ICON_APPEAR_AMOUNT,
+ targetAmount);
+ mIconAppearAnimator.setInterpolator(interpolator);
+ mIconAppearAnimator.setDuration(100);
+ mIconAppearAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIconAppearAnimator = null;
+ }
+ });
+ mIconAppearAnimator.start();
+
+ if (mDotAnimator != null) {
+ mDotAnimator.cancel();
+ }
+ targetAmount = visibleState == STATE_ICON ? 2.0f : 0.0f;
+ interpolator = Interpolators.FAST_OUT_LINEAR_IN;
+ if (visibleState == STATE_DOT) {
+ targetAmount = 1.0f;
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN;
+ }
+ mDotAnimator = ObjectAnimator.ofFloat(this, DOT_APPEAR_AMOUNG,
+ targetAmount);
+ mDotAnimator.setInterpolator(interpolator);
+ mDotAnimator.setDuration(100);
+ mDotAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mDotAnimator = null;
+ }
+ });
+ mDotAnimator.start();
+ }
+ }
+
+ public void setIconAppearAmount(Float iconAppearAmount) {
+ mIconAppearAmount = iconAppearAmount;
+ invalidate();
+ }
+
+ public float getIconAppearAmount() {
+ return mIconAppearAmount;
+ }
+
+ public int getVisibleState() {
+ return mVisibleState;
+ }
+
+ public void setDotAppearAmount(float dotAppearAmount) {
+ mDotAppearAmount = dotAppearAmount;
+ invalidate();
+ }
+
+ public float getDotAppearAmount() {
+ return mDotAppearAmount;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 72e84a464fd2..7b67f31b7a4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -8,7 +8,6 @@ import android.graphics.Rect;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
import android.widget.LinearLayout;
import com.android.internal.util.NotificationColorUtil;
@@ -36,7 +35,6 @@ public class NotificationIconAreaController {
private PhoneStatusBar mPhoneStatusBar;
protected View mNotificationIconArea;
- private NotificationShelf mNotificationIconAreaScroller;
private NotificationIconContainer mNotificationIcons;
private NotificationIconContainer mNotificationIconsScroller;
private final Rect mTintArea = new Rect();
@@ -66,8 +64,9 @@ public class NotificationIconAreaController {
mNotificationIcons = (NotificationIconContainer) mNotificationIconArea.findViewById(
R.id.notificationIcons);
- mNotificationIconAreaScroller = mPhoneStatusBar.getNotificationShelf();
- mNotificationIconsScroller = mNotificationIconAreaScroller.getNotificationIconContainer();
+ NotificationShelf shelf = mPhoneStatusBar.getNotificationShelf();
+ mNotificationIconsScroller = shelf.getShelfIcons();
+ shelf.setCollapsedIcons(mNotificationIcons);
mNotificationScrollLayout = mPhoneStatusBar.getNotificationScrollLayout();
}
@@ -115,12 +114,10 @@ public class NotificationIconAreaController {
}
/**
- * Sets the color that should be used to tint any icons in the notification area. If this
- * method is not called, the default tint is {@link Color#WHITE}.
+ * Sets the color that should be used to tint any icons in the notification area.
*/
public void setIconTint(int iconTint) {
mIconTint = iconTint;
- mNotificationIcons.setIconTint(mIconTint);
applyNotificationIconsTint();
}
@@ -178,7 +175,7 @@ public class NotificationIconAreaController {
*/
private void updateIconsForLayout(NotificationData notificationData,
Function<NotificationData.Entry, StatusBarIconView> function,
- ViewGroup hostLayout) {
+ NotificationIconContainer hostLayout) {
ArrayList<StatusBarIconView> toShow = new ArrayList<>(
mNotificationScrollLayout.getChildCount());
@@ -193,6 +190,7 @@ public class NotificationIconAreaController {
}
}
+
ArrayList<View> toRemove = new ArrayList<>();
for (int i = 0; i < hostLayout.getChildCount(); i++) {
View child = hostLayout.getChildAt(i);
@@ -239,6 +237,7 @@ public class NotificationIconAreaController {
v.setImageTintList(ColorStateList.valueOf(
StatusBarIconController.getTint(mTintArea, v, mIconTint)));
}
+ v.setIconTint(mIconTint);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 11563d5945cd..0f41e31d9b36 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -17,10 +17,18 @@
package com.android.systemui.statusbar.phone;
import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
+import com.android.systemui.R;
import com.android.systemui.statusbar.AlphaOptimizedFrameLayout;
+import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.stack.AnimationFilter;
+import com.android.systemui.statusbar.stack.AnimationProperties;
import com.android.systemui.statusbar.stack.ViewState;
import java.util.WeakHashMap;
@@ -31,16 +39,49 @@ import java.util.WeakHashMap;
*/
public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
private static final String TAG = "NotificationIconContainer";
+ private static final boolean DEBUG = false;
+ private static final AnimationFilter DOT_ANIMATION_FILTER = new AnimationFilter().animateX();
+ private static final AnimationProperties DOT_ANIMATION_PROPERTIES = new AnimationProperties() {
+ @Override
+ public AnimationFilter getAnimationFilter() {
+ return DOT_ANIMATION_FILTER;
+ }
+ }.setDuration(200);
private boolean mShowAllIcons = true;
- private int mIconTint;
private WeakHashMap<View, IconState> mIconStates = new WeakHashMap<>();
+ private int mDotPadding;
+ private int mStaticDotRadius;
+ private int mActualLayoutWidth = -1;
+ private float mActualPaddingEnd = -1;
+ private float mActualPaddingStart = -1;
public NotificationIconContainer(Context context, AttributeSet attrs) {
super(context, attrs);
+ initDimens();
+ setWillNotDraw(!DEBUG);
+ }
+
+ private void initDimens() {
+ mDotPadding = getResources().getDimensionPixelSize(R.dimen.overflow_icon_dot_padding);
+ mStaticDotRadius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ Paint paint = new Paint();
+ paint.setColor(Color.RED);
+ paint.setStyle(Paint.Style.STROKE);
+ canvas.drawRect(getActualPaddingStart(), 0, getLayoutEnd(), getHeight(), paint);
}
@Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ initDimens();
+ }
+ @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
float centerY = getHeight() / 2.0f;
// we layout all our children on the left at the top
@@ -82,10 +123,6 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
mIconStates.remove(child);
}
- public void setIconTint(int iconTint) {
- mIconTint = iconTint;
- }
-
public WeakHashMap<View, IconState> resetViewStates() {
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
@@ -100,17 +137,75 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
* are inserted into the notification container.
* If this is not a whole number, the fraction means by how much the icon is appearing.
*/
- public WeakHashMap<View, IconState> calculateIconTranslations() {
+ public void calculateIconTranslations() {
+ float translationX = getActualPaddingStart();
+ int overflowingIconIndex = -1;
+ int lastTwoIconWidth = 0;
int childCount = getChildCount();
- float visibleIconStart = childCount - numberOfVisibleIcons;
- float translationX = 0.0f;
for (int i = 0; i < childCount; i++) {
View view = getChildAt(i);
IconState iconState = mIconStates.get(view);
iconState.xTranslation = translationX;
+ iconState.visibleState = StatusBarIconView.STATE_ICON;
translationX += iconState.iconAppearAmount * view.getWidth();
+ if (translationX > getLayoutEnd()) {
+ // we are overflowing it with this icon
+ overflowingIconIndex = i - 1;
+ lastTwoIconWidth = view.getWidth();
+ break;
+ }
}
- return mIconStates;
+ if (overflowingIconIndex != -1) {
+ int numDots = 1;
+ View overflowIcon = getChildAt(overflowingIconIndex);
+ IconState overflowState = mIconStates.get(overflowIcon);
+ lastTwoIconWidth += overflowIcon.getWidth();
+ int dotWidth = mStaticDotRadius * 2 + mDotPadding;
+ int totalDotLength = mStaticDotRadius * 6 + 2 * mDotPadding;
+ translationX = (getLayoutEnd() - lastTwoIconWidth / 2 - totalDotLength / 2)
+ - overflowIcon.getWidth() * 0.3f + mStaticDotRadius;
+ float overflowStart = getLayoutEnd() - lastTwoIconWidth;
+ float overlapAmount = (overflowState.xTranslation - overflowStart)
+ / overflowIcon.getWidth();
+ translationX += overlapAmount * dotWidth;
+ for (int i = overflowingIconIndex; i < childCount; i++) {
+ View view = getChildAt(i);
+ IconState iconState = mIconStates.get(view);
+ iconState.xTranslation = translationX;
+ if (numDots <= 3) {
+ iconState.visibleState = StatusBarIconView.STATE_DOT;
+ translationX += numDots == 3 ? 3 * dotWidth : dotWidth;
+ } else {
+ iconState.visibleState = StatusBarIconView.STATE_HIDDEN;
+ }
+ numDots++;
+ }
+ }
+ if (isLayoutRtl()) {
+ for (int i = 0; i < childCount; i++) {
+ View view = getChildAt(i);
+ IconState iconState = mIconStates.get(view);
+ iconState.xTranslation = getWidth() - iconState.xTranslation - view.getWidth();
+ }
+ }
+ }
+
+ private float getLayoutEnd() {
+ return getActualWidth() - getActualPaddingEnd();
+ }
+
+ private float getActualPaddingEnd() {
+ if (mActualPaddingEnd < 0) {
+ return getPaddingEnd();
+ }
+ return mActualPaddingEnd;
+ }
+
+ private float getActualPaddingStart() {
+ if (mActualPaddingStart < 0) {
+ return getPaddingStart();
+ }
+ return mActualPaddingStart;
}
/**
@@ -123,12 +218,49 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
mShowAllIcons = showAllIcons;
}
+ public void setActualLayoutWidth(int actualLayoutWidth) {
+ mActualLayoutWidth = actualLayoutWidth;
+ if (DEBUG) {
+ invalidate();
+ }
+ }
+
+ public void setActualPaddingEnd(float paddingEnd) {
+ mActualPaddingEnd = paddingEnd;
+ if (DEBUG) {
+ invalidate();
+ }
+ }
+
+ public void setActualPaddingStart(float paddingStart) {
+ mActualPaddingStart = paddingStart;
+ if (DEBUG) {
+ invalidate();
+ }
+ }
+
+ public int getActualWidth() {
+ if (mActualLayoutWidth < 0) {
+ return getWidth();
+ }
+ return mActualLayoutWidth;
+ }
+
public static class IconState extends ViewState {
public float iconAppearAmount = 1.0f;
+ public int visibleState;
@Override
public void applyToView(View view) {
- super.applyToView(view);
+ if (view instanceof StatusBarIconView) {
+ StatusBarIconView icon = (StatusBarIconView) view;
+ if (visibleState != icon.getVisibleState()) {
+ icon.setVisibleState(visibleState);
+ animateTo(icon, DOT_ANIMATION_PROPERTIES);
+ } else {
+ super.applyToView(view);
+ }
+ }
}
}
}