Update notification visuals (part 2)
- Background is now white, and color beneath and divider color
updated accordingly (not from color extraction)
- Removed overflow text ("+6") and added it to a header
("6 Notifications"). Use "..." instead if there is an overflow.
- Even spaced out icons in notification footer between the
far right icon and the ellipsis
- Remove code to change arrow tint, since it is always white
now. This also fixes the issue where it was drawn as a rect.
Bug: 35766387
Change-Id: I03bfda4ff029f23dd8b3dd1b72f534ea0e2c0816
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="@dimen/horizontal_ellipsis_size"
|
||||
android:height="@dimen/horizontal_ellipsis_size"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0"
|
||||
android:tint="?android:attr/textColorSecondary" >
|
||||
|
||||
<path
|
||||
android:pathData="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
|
||||
android:fillColor="@android:color/white" />
|
||||
</vector>
|
||||
@@ -20,7 +20,8 @@
|
||||
android:layout_width="@dimen/bg_popup_item_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="@dimen/deep_shortcuts_elevation"
|
||||
android:background="@drawable/bg_white_round_rect">
|
||||
android:background="@drawable/bg_white_round_rect"
|
||||
android:backgroundTint="@color/notification_color_beneath">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
@@ -28,16 +29,49 @@
|
||||
android:orientation="vertical"
|
||||
android:clipChildren="false">
|
||||
|
||||
<com.android.launcher3.notification.NotificationHeaderView
|
||||
android:id="@+id/header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/notification_header_height"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="@dimen/notification_padding"
|
||||
android:background="@color/notification_header_background_color"
|
||||
android:elevation="@dimen/notification_elevation">
|
||||
<TextView
|
||||
android:id="@+id/notification_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="start|center_vertical"
|
||||
android:paddingEnd="@dimen/notification_header_padding_after_count"
|
||||
android:textSize="@dimen/notification_main_text_size"
|
||||
android:textColor="?android:attr/textColorPrimary" />
|
||||
<TextView
|
||||
android:id="@+id/notification_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="start|center_vertical"
|
||||
android:textSize="@dimen/notification_main_text_size"
|
||||
android:textColor="?android:attr/textColorSecondary" />
|
||||
</com.android.launcher3.notification.NotificationHeaderView>
|
||||
|
||||
<include layout="@layout/notification_main"
|
||||
android:id="@+id/main_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/notification_main_height" />
|
||||
android:layout_height="@dimen/notification_main_height"
|
||||
android:layout_below="@id/header" />
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/popup_item_divider_height"
|
||||
android:background="@color/divider_color"
|
||||
android:layout_below="@id/main_view"/>
|
||||
|
||||
<include layout="@layout/notification_footer"
|
||||
android:id="@+id/footer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/notification_footer_height"
|
||||
android:layout_below="@id/main_view" />
|
||||
android:layout_below="@id/divider" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
@@ -18,25 +18,29 @@
|
||||
<com.android.launcher3.notification.NotificationFooterLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:elevation="@dimen/notification_elevation"
|
||||
android:clipChildren="false" >
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/popup_item_divider_height"/>
|
||||
android:clipChildren="false"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:background="@color/notification_background_color">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/icon_row"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="end"
|
||||
android:gravity="end|center_vertical"
|
||||
android:padding="@dimen/notification_footer_icon_row_padding"
|
||||
android:clipToPadding="false"
|
||||
android:clipChildren="false"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/overflow"
|
||||
android:layout_width="@dimen/horizontal_ellipsis_size"
|
||||
android:layout_height="@dimen/horizontal_ellipsis_size"
|
||||
android:background="@drawable/horizontal_ellipsis"
|
||||
android:layout_marginStart="@dimen/horizontal_ellipsis_offset"
|
||||
android:layout_gravity="start|center_vertical" />
|
||||
|
||||
</com.android.launcher3.notification.NotificationFooterLayout>
|
||||
|
||||
|
||||
@@ -19,43 +19,46 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:focusable="true"
|
||||
android:padding="@dimen/notification_padding"
|
||||
android:elevation="@dimen/notification_elevation" >
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/text_and_background"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center_vertical">
|
||||
android:gravity="center_vertical"
|
||||
android:background="@color/notification_background_color"
|
||||
android:paddingStart="@dimen/notification_padding"
|
||||
android:paddingEnd="@dimen/notification_main_text_padding_end">
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="viewStart"
|
||||
android:fontFamily="sans-serif"
|
||||
android:textSize="14sp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
android:textSize="@dimen/notification_main_text_size"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:lines="1"
|
||||
android:ellipsize="end" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
android:paddingEnd="4dp"
|
||||
android:textSize="12sp"
|
||||
android:textAlignment="viewStart"
|
||||
android:fontFamily="sans-serif"
|
||||
android:textColor="?android:attr/textColorTertiary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif"
|
||||
android:textSize="@dimen/notification_main_text_size"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:lines="1"
|
||||
android:ellipsize="end" />
|
||||
</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" />
|
||||
android:layout_marginEnd="@dimen/notification_padding"
|
||||
android:layout_gravity="center_vertical|end" />
|
||||
|
||||
</com.android.launcher3.notification.NotificationMainView>
|
||||
|
||||
|
||||
@@ -36,4 +36,8 @@
|
||||
<color name="spring_loaded_highlighted_panel_border_color">#FFF</color>
|
||||
|
||||
<color name="notification_icon_default_color">#757575</color> <!-- Gray 600 -->
|
||||
<color name="notification_header_background_color">#F5F5F5</color> <!-- Gray 100 -->
|
||||
<color name="notification_background_color">#FFF</color>
|
||||
<color name="notification_color_beneath">#E0E0E0</color> <!-- Gray 300 -->
|
||||
<color name="divider_color">@color/notification_color_beneath</color>
|
||||
</resources>
|
||||
|
||||
+13
-4
@@ -178,17 +178,26 @@
|
||||
<dimen name="badge_text_size">12dp</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>
|
||||
<dimen name="notification_icon_size">24dp</dimen>
|
||||
<dimen name="notification_footer_icon_size">18dp</dimen>
|
||||
|
||||
<!-- 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>
|
||||
<!-- notification_padding + (icon_size - footer_icon_size) / 2 -->
|
||||
<dimen name="notification_footer_icon_row_padding">15dp</dimen>
|
||||
<dimen name="notification_header_padding_after_count">8dp</dimen>
|
||||
<dimen name="notification_header_height">32dp</dimen>
|
||||
<dimen name="notification_main_height">60dp</dimen>
|
||||
<dimen name="notification_footer_height">@dimen/bg_popup_item_height</dimen>
|
||||
<dimen name="notification_header_text_size">12dp</dimen>
|
||||
<dimen name="notification_main_text_size">14dp</dimen>
|
||||
<!-- notification_icon_size + notification+padding + padding we want between icon and text -->
|
||||
<dimen name="notification_main_text_padding_end">40dp</dimen>
|
||||
<dimen name="notification_elevation">2dp</dimen>
|
||||
<dimen name="horizontal_ellipsis_size">18dp</dimen>
|
||||
<!-- arrow_horizontal_offset - (ellipsis_size - arrow_width) / 2 -->
|
||||
<dimen name="horizontal_ellipsis_offset">15dp</dimen>
|
||||
<dimen name="popup_item_divider_height">0.5dp</dimen>
|
||||
<dimen name="swipe_helper_falsing_threshold">70dp</dimen>
|
||||
|
||||
|
||||
@@ -72,7 +72,10 @@
|
||||
The text must fit in the size of a small icon [CHAR_LIMIT=3] -->
|
||||
<string name="deep_notifications_overflow" translatable="false">+%1$d</string>
|
||||
<!-- Text to display as the header above notifications. [CHAR_LIMIT=30] -->
|
||||
<string name="notifications_header" translatable="false">Notifications</string>
|
||||
<plurals name="notifications_header" translatable="false">
|
||||
<item quantity="one">Notification</item>
|
||||
<item quantity="other">Notifications</item>
|
||||
</plurals>
|
||||
|
||||
<!-- Drag and drop -->
|
||||
<skip />
|
||||
|
||||
@@ -42,9 +42,9 @@ import com.android.launcher3.badge.BadgeRenderer;
|
||||
import com.android.launcher3.folder.FolderIcon;
|
||||
import com.android.launcher3.graphics.DrawableFactory;
|
||||
import com.android.launcher3.graphics.HolographicOutlineHelper;
|
||||
import com.android.launcher3.graphics.IconPalette;
|
||||
import com.android.launcher3.graphics.PreloadIconDrawable;
|
||||
import com.android.launcher3.model.PackageItemInfo;
|
||||
import com.android.launcher3.popup.PopupContainerWithArrow;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
|
||||
@@ -502,15 +502,14 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
|
||||
if (mIcon instanceof FastBitmapDrawable) {
|
||||
BadgeInfo badgeInfo = mLauncher.getPopupDataProvider().getBadgeInfoForItem(itemInfo);
|
||||
BadgeRenderer badgeRenderer = mLauncher.getDeviceProfile().mBadgeRenderer;
|
||||
PopupContainerWithArrow popup = PopupContainerWithArrow.getOpen(mLauncher);
|
||||
if (popup != null) {
|
||||
popup.updateNotificationHeader(badgeInfo, itemInfo);
|
||||
}
|
||||
((FastBitmapDrawable) mIcon).applyIconBadge(badgeInfo, badgeRenderer, animate);
|
||||
}
|
||||
}
|
||||
|
||||
public IconPalette getIconPalette() {
|
||||
return mIcon instanceof FastBitmapDrawable ? ((FastBitmapDrawable) mIcon).getIconPalette()
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the icon for this view based on the layout direction.
|
||||
*/
|
||||
|
||||
@@ -167,7 +167,7 @@ public class FastBitmapDrawable extends Drawable {
|
||||
}
|
||||
}
|
||||
|
||||
public IconPalette getIconPalette() {
|
||||
protected IconPalette getIconPalette() {
|
||||
if (mIconPalette == null) {
|
||||
mIconPalette = IconPalette.fromDominantColor(Utilities
|
||||
.findDominantColorByHue(mBitmap, 20));
|
||||
|
||||
@@ -21,14 +21,15 @@ import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
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.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAnimUtils;
|
||||
@@ -36,7 +37,6 @@ 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -44,16 +44,16 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A {@link LinearLayout} that contains only icons of notifications.
|
||||
* If there are more than {@link #MAX_FOOTER_NOTIFICATIONS} icons, we add a "+x" overflow.
|
||||
* A {@link FrameLayout} that contains only icons of notifications.
|
||||
* If there are more than {@link #MAX_FOOTER_NOTIFICATIONS} icons, we add a "..." overflow.
|
||||
*/
|
||||
public class NotificationFooterLayout extends LinearLayout {
|
||||
public class NotificationFooterLayout extends FrameLayout {
|
||||
|
||||
public interface IconAnimationEndListener {
|
||||
void onIconAnimationEnd(NotificationInfo animatedNotification);
|
||||
}
|
||||
|
||||
private static final int MAX_FOOTER_NOTIFICATIONS = 4;
|
||||
private static final int MAX_FOOTER_NOTIFICATIONS = 5;
|
||||
|
||||
private static final Rect sTempRect = new Rect();
|
||||
|
||||
@@ -61,11 +61,10 @@ public class NotificationFooterLayout extends LinearLayout {
|
||||
private final List<NotificationInfo> mOverflowNotifications = new ArrayList<>();
|
||||
private final boolean mRtl;
|
||||
|
||||
LinearLayout.LayoutParams mIconLayoutParams;
|
||||
FrameLayout.LayoutParams mIconLayoutParams;
|
||||
private View mOverflowEllipsis;
|
||||
private LinearLayout mIconRow;
|
||||
private final ColorDrawable mBackgroundColor;
|
||||
private int mTextColor;
|
||||
private TextView mOverflowView;
|
||||
private int mBackgroundColor;
|
||||
|
||||
public NotificationFooterLayout(Context context) {
|
||||
this(context, null, 0);
|
||||
@@ -78,33 +77,29 @@ public class NotificationFooterLayout extends LinearLayout {
|
||||
public NotificationFooterLayout(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
mRtl = Utilities.isRtl(getResources());
|
||||
Resources res = getResources();
|
||||
mRtl = Utilities.isRtl(res);
|
||||
|
||||
int size = getResources().getDimensionPixelSize(
|
||||
R.dimen.notification_footer_icon_size);
|
||||
int padding = getResources().getDimensionPixelSize(R.dimen.notification_padding);
|
||||
mIconLayoutParams = new LayoutParams(size, size);
|
||||
mIconLayoutParams.setMarginEnd(padding);
|
||||
int iconSize = res.getDimensionPixelSize(R.dimen.notification_footer_icon_size);
|
||||
mIconLayoutParams = new LayoutParams(iconSize, iconSize);
|
||||
mIconLayoutParams.gravity = Gravity.CENTER_VERTICAL;
|
||||
|
||||
mBackgroundColor = new ColorDrawable();
|
||||
setBackground(mBackgroundColor);
|
||||
// Compute margin start for each icon such that the icons between the first one
|
||||
// and the ellipsis are evenly spaced out.
|
||||
int paddingEnd = res.getDimensionPixelSize(R.dimen.notification_footer_icon_row_padding);
|
||||
int ellipsisSpace = res.getDimensionPixelSize(R.dimen.horizontal_ellipsis_offset)
|
||||
+ res.getDimensionPixelSize(R.dimen.horizontal_ellipsis_size);
|
||||
int footerWidth = res.getDimensionPixelSize(R.dimen.bg_popup_item_width);
|
||||
int availableIconRowSpace = footerWidth - paddingEnd - ellipsisSpace
|
||||
- iconSize * MAX_FOOTER_NOTIFICATIONS;
|
||||
mIconLayoutParams.setMarginStart(availableIconRowSpace / MAX_FOOTER_NOTIFICATIONS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mOverflowEllipsis = findViewById(R.id.overflow);
|
||||
mIconRow = (LinearLayout) findViewById(R.id.icon_row);
|
||||
}
|
||||
|
||||
public void applyColors(IconPalette iconPalette) {
|
||||
mBackgroundColor.setColor(iconPalette.backgroundColor);
|
||||
findViewById(R.id.divider).setBackgroundColor(iconPalette.secondaryColor);
|
||||
mTextColor = iconPalette.textColor;
|
||||
}
|
||||
|
||||
public int getBackgroundColor() {
|
||||
return mBackgroundColor.getColor();
|
||||
mBackgroundColor = ((ColorDrawable) getBackground()).getColor();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,35 +123,26 @@ public class NotificationFooterLayout extends LinearLayout {
|
||||
|
||||
for (int i = 0; i < mNotifications.size(); i++) {
|
||||
NotificationInfo info = mNotifications.get(i);
|
||||
addNotificationIconForInfo(info, false /* fromOverflow */);
|
||||
}
|
||||
|
||||
if (!mOverflowNotifications.isEmpty()) {
|
||||
mOverflowView = new TextView(getContext());
|
||||
mOverflowView.setTextColor(mTextColor);
|
||||
updateOverflowText();
|
||||
mIconRow.addView(mOverflowView, 0, mIconLayoutParams);
|
||||
addNotificationIconForInfo(info);
|
||||
}
|
||||
updateOverflowEllipsisVisibility();
|
||||
}
|
||||
|
||||
private void addNotificationIconForInfo(NotificationInfo info, boolean fromOverflow) {
|
||||
private void updateOverflowEllipsisVisibility() {
|
||||
mOverflowEllipsis.setVisibility(mOverflowNotifications.isEmpty() ? GONE : VISIBLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an icon for the given NotificationInfo, and adds it to the icon row.
|
||||
* @return the icon view that was added
|
||||
*/
|
||||
private View addNotificationIconForInfo(NotificationInfo info) {
|
||||
View icon = new View(getContext());
|
||||
icon.setBackground(info.getIconForBackground(getContext(), getBackgroundColor()));
|
||||
icon.setBackground(info.getIconForBackground(getContext(), mBackgroundColor));
|
||||
icon.setOnClickListener(info);
|
||||
int addIndex = 0;
|
||||
if (fromOverflow) {
|
||||
// Add the notification before the overflow view.
|
||||
addIndex = 1;
|
||||
icon.setAlpha(0);
|
||||
icon.animate().alpha(1);
|
||||
}
|
||||
icon.setTag(info);
|
||||
mIconRow.addView(icon, addIndex, mIconLayoutParams);
|
||||
}
|
||||
|
||||
private void updateOverflowText() {
|
||||
mOverflowView.setText(getResources().getString(R.string.deep_notifications_overflow,
|
||||
mOverflowNotifications.size()));
|
||||
mIconRow.addView(icon, 0, mIconLayoutParams);
|
||||
return icon;
|
||||
}
|
||||
|
||||
public void animateFirstNotificationTo(Rect toBounds,
|
||||
@@ -180,16 +166,22 @@ public class NotificationFooterLayout extends LinearLayout {
|
||||
animation.play(moveAndScaleIcon);
|
||||
|
||||
// Shift all notifications (not the overflow) over to fill the gap.
|
||||
int gapWidth = mIconLayoutParams.width + mIconLayoutParams.getMarginEnd();
|
||||
int gapWidth = mIconLayoutParams.width + mIconLayoutParams.getMarginStart();
|
||||
if (mRtl) {
|
||||
gapWidth = -gapWidth;
|
||||
}
|
||||
int numIcons = mIconRow.getChildCount() - 1;
|
||||
// We have to set the translation X to 0 when the new main notification
|
||||
if (!mOverflowNotifications.isEmpty()) {
|
||||
NotificationInfo notification = mOverflowNotifications.remove(0);
|
||||
mNotifications.add(notification);
|
||||
View iconFromOverflow = addNotificationIconForInfo(notification);
|
||||
animation.play(ObjectAnimator.ofFloat(iconFromOverflow, ALPHA, 0, 1));
|
||||
}
|
||||
int numIcons = mIconRow.getChildCount() - 1; // All children besides the one leaving.
|
||||
// We have to reset 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++) {
|
||||
for (int i = 0; i < numIcons; i++) {
|
||||
final View child = mIconRow.getChildAt(i);
|
||||
Animator shiftChild = ObjectAnimator.ofFloat(child, TRANSLATION_X, gapWidth);
|
||||
shiftChild.addListener(propertyResetListener);
|
||||
@@ -201,19 +193,7 @@ public class NotificationFooterLayout extends LinearLayout {
|
||||
private void removeViewFromIconRow(View child) {
|
||||
mIconRow.removeView(child);
|
||||
mNotifications.remove((NotificationInfo) child.getTag());
|
||||
if (!mOverflowNotifications.isEmpty()) {
|
||||
NotificationInfo notification = mOverflowNotifications.remove(0);
|
||||
mNotifications.add(notification);
|
||||
addNotificationIconForInfo(notification, true /* fromOverflow */);
|
||||
}
|
||||
if (mOverflowView != null) {
|
||||
if (mOverflowNotifications.isEmpty()) {
|
||||
mIconRow.removeView(mOverflowView);
|
||||
mOverflowView = null;
|
||||
} else {
|
||||
updateOverflowText();
|
||||
}
|
||||
}
|
||||
updateOverflowEllipsisVisibility();
|
||||
if (mIconRow.getChildCount() == 0) {
|
||||
// There are no more icons in the footer, so hide it.
|
||||
PopupContainerWithArrow popup = PopupContainerWithArrow.getOpen(
|
||||
@@ -240,16 +220,11 @@ public class NotificationFooterLayout extends LinearLayout {
|
||||
overflowIterator.remove();
|
||||
}
|
||||
}
|
||||
TextView overflowView = null;
|
||||
for (int i = mIconRow.getChildCount() - 1; i >= 0; i--) {
|
||||
View child = mIconRow.getChildAt(i);
|
||||
if (child instanceof TextView) {
|
||||
overflowView = (TextView) child;
|
||||
} else {
|
||||
NotificationInfo childInfo = (NotificationInfo) child.getTag();
|
||||
if (!notifications.contains(childInfo.notificationKey)) {
|
||||
removeViewFromIconRow(child);
|
||||
}
|
||||
NotificationInfo childInfo = (NotificationInfo) child.getTag();
|
||||
if (!notifications.contains(childInfo.notificationKey)) {
|
||||
removeViewFromIconRow(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.notification;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
|
||||
/**
|
||||
* A {@link LinearLayout} that contains two text views: one for the notification count
|
||||
* and one just to say "Notification" or "Notifications"
|
||||
*/
|
||||
public class NotificationHeaderView extends LinearLayout {
|
||||
|
||||
private TextView mNotificationCount;
|
||||
private TextView mNotificationText;
|
||||
|
||||
public NotificationHeaderView(Context context) {
|
||||
this(context, null, 0);
|
||||
}
|
||||
|
||||
public NotificationHeaderView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public NotificationHeaderView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mNotificationCount = (TextView) findViewById(R.id.notification_count);
|
||||
mNotificationText = (TextView) findViewById(R.id.notification_text);
|
||||
}
|
||||
|
||||
public void update(int notificationCount) {
|
||||
mNotificationCount.setText(String.valueOf(notificationCount));
|
||||
mNotificationText.setText(getResources().getQuantityString(
|
||||
R.plurals.notifications_header, notificationCount));
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ package com.android.launcher3.notification;
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
@@ -30,7 +29,6 @@ import android.widget.FrameLayout;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.anim.PillHeightRevealOutlineProvider;
|
||||
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;
|
||||
@@ -47,7 +45,7 @@ public class NotificationItemView extends PopupItemView implements LogContainerP
|
||||
|
||||
private static final Rect sTempRect = new Rect();
|
||||
|
||||
private View mDivider;
|
||||
private NotificationHeaderView mHeader;
|
||||
private NotificationMainView mMainView;
|
||||
private NotificationFooterLayout mFooter;
|
||||
private SwipeHelper mSwipeHelper;
|
||||
@@ -68,7 +66,7 @@ public class NotificationItemView extends PopupItemView implements LogContainerP
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mDivider = findViewById(R.id.divider);
|
||||
mHeader = (NotificationHeaderView) findViewById(R.id.header);
|
||||
mMainView = (NotificationMainView) findViewById(R.id.main_view);
|
||||
mFooter = (NotificationFooterLayout) findViewById(R.id.footer);
|
||||
mSwipeHelper = new SwipeHelper(SwipeHelper.X, mMainView, getContext());
|
||||
@@ -95,6 +93,10 @@ public class NotificationItemView extends PopupItemView implements LogContainerP
|
||||
return heightAnimator;
|
||||
}
|
||||
|
||||
public void updateHeader(int notificationCount) {
|
||||
mHeader.update(notificationCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
if (mMainView.getNotificationInfo() == null) {
|
||||
@@ -114,13 +116,6 @@ public class NotificationItemView extends PopupItemView implements LogContainerP
|
||||
return mSwipeHelper.onTouchEvent(ev) || super.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ColorStateList getAttachedArrowColor() {
|
||||
// This NotificationView itself has a different color that is only
|
||||
// revealed when dismissing notifications.
|
||||
return ColorStateList.valueOf(mFooter.getBackgroundColor());
|
||||
}
|
||||
|
||||
public void applyNotificationInfos(final List<NotificationInfo> notificationInfos) {
|
||||
if (notificationInfos.isEmpty()) {
|
||||
return;
|
||||
@@ -135,13 +130,6 @@ public class NotificationItemView extends PopupItemView implements LogContainerP
|
||||
mFooter.commitNotificationInfos();
|
||||
}
|
||||
|
||||
public void applyColors(IconPalette iconPalette) {
|
||||
setBackgroundTintList(ColorStateList.valueOf(iconPalette.secondaryColor));
|
||||
mDivider.setBackgroundColor(iconPalette.secondaryColor);
|
||||
mMainView.applyColors(iconPalette);
|
||||
mFooter.applyColors(iconPalette);
|
||||
}
|
||||
|
||||
public void trimNotifications(final List<String> notificationKeys) {
|
||||
boolean dismissedMainNotification = !notificationKeys.contains(
|
||||
mMainView.getNotificationInfo().notificationKey);
|
||||
|
||||
@@ -16,11 +16,7 @@
|
||||
|
||||
package com.android.launcher3.notification;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ArgbEvaluator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
@@ -28,28 +24,27 @@ import android.graphics.drawable.RippleDrawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAnimUtils;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.graphics.IconPalette;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.util.Themes;
|
||||
|
||||
/**
|
||||
* A {@link LinearLayout} that contains a single notification, e.g. icon + title + text.
|
||||
* A {@link android.widget.FrameLayout} that contains a single notification,
|
||||
* e.g. icon + title + text.
|
||||
*/
|
||||
public class NotificationMainView extends LinearLayout implements SwipeHelper.Callback {
|
||||
|
||||
private final ArgbEvaluator mArgbEvaluator = new ArgbEvaluator();
|
||||
public class NotificationMainView extends FrameLayout implements SwipeHelper.Callback {
|
||||
|
||||
private NotificationInfo mNotificationInfo;
|
||||
private ViewGroup mTextAndBackground;
|
||||
private int mBackgroundColor;
|
||||
private TextView mTitleView;
|
||||
private TextView mTextView;
|
||||
private IconPalette mIconPalette;
|
||||
private ColorDrawable mColorBackground;
|
||||
|
||||
public NotificationMainView(Context context) {
|
||||
this(context, null, 0);
|
||||
@@ -67,16 +62,15 @@ public class NotificationMainView extends LinearLayout implements SwipeHelper.Ca
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
mTitleView = (TextView) findViewById(R.id.title);
|
||||
mTextView = (TextView) findViewById(R.id.text);
|
||||
}
|
||||
|
||||
public void applyColors(IconPalette iconPalette) {
|
||||
mColorBackground = new ColorDrawable(iconPalette.backgroundColor);
|
||||
RippleDrawable rippleDrawable = new RippleDrawable(ColorStateList.valueOf(
|
||||
iconPalette.secondaryColor), mColorBackground, null);
|
||||
setBackground(rippleDrawable);
|
||||
mIconPalette = iconPalette;
|
||||
mTextAndBackground = (ViewGroup) findViewById(R.id.text_and_background);
|
||||
ColorDrawable colorBackground = (ColorDrawable) mTextAndBackground.getBackground();
|
||||
mBackgroundColor = colorBackground.getColor();
|
||||
RippleDrawable rippleBackground = new RippleDrawable(ColorStateList.valueOf(
|
||||
Themes.getAttrColor(getContext(), android.R.attr.colorControlHighlight)),
|
||||
colorBackground, null);
|
||||
mTextAndBackground.setBackground(rippleBackground);
|
||||
mTitleView = (TextView) mTextAndBackground.findViewById(R.id.title);
|
||||
mTextView = (TextView) mTextAndBackground.findViewById(R.id.text);
|
||||
}
|
||||
|
||||
public void applyNotificationInfo(NotificationInfo mainNotification, View iconView) {
|
||||
@@ -88,30 +82,18 @@ public class NotificationMainView extends LinearLayout implements SwipeHelper.Ca
|
||||
*/
|
||||
public void applyNotificationInfo(NotificationInfo mainNotification, View iconView,
|
||||
boolean animate) {
|
||||
if (animate) {
|
||||
mTitleView.setAlpha(0);
|
||||
mTextView.setAlpha(0);
|
||||
mColorBackground.setColor(mIconPalette.secondaryColor);
|
||||
}
|
||||
mNotificationInfo = mainNotification;
|
||||
mTitleView.setText(mNotificationInfo.title);
|
||||
mTextView.setText(mNotificationInfo.text);
|
||||
iconView.setBackground(mNotificationInfo.getIconForBackground(
|
||||
getContext(), mIconPalette.backgroundColor));
|
||||
iconView.setBackground(mNotificationInfo.getIconForBackground(getContext(),
|
||||
mBackgroundColor));
|
||||
setOnClickListener(mNotificationInfo);
|
||||
setTranslationX(0);
|
||||
// Add a dummy ItemInfo so that logging populates the correct container and item types
|
||||
// instead of DEFAULT_CONTAINERTYPE and DEFAULT_ITEMTYPE, respectively.
|
||||
setTag(new ItemInfo());
|
||||
if (animate) {
|
||||
AnimatorSet animation = LauncherAnimUtils.createAnimatorSet();
|
||||
Animator textFade = ObjectAnimator.ofFloat(mTextView, View.ALPHA, 1);
|
||||
Animator titleFade = ObjectAnimator.ofFloat(mTitleView, View.ALPHA, 1);
|
||||
ValueAnimator colorChange = ObjectAnimator.ofObject(mColorBackground, "color",
|
||||
mArgbEvaluator, mIconPalette.secondaryColor, mIconPalette.backgroundColor);
|
||||
animation.playTogether(textFade, titleFade, colorChange);
|
||||
animation.setDuration(150);
|
||||
animation.start();
|
||||
ObjectAnimator.ofFloat(mTextAndBackground, ALPHA, 0, 1).setDuration(150).start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,14 +63,12 @@ import com.android.launcher3.badge.BadgeInfo;
|
||||
import com.android.launcher3.dragndrop.DragController;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.dragndrop.DragOptions;
|
||||
import com.android.launcher3.graphics.IconPalette;
|
||||
import com.android.launcher3.graphics.TriangleShape;
|
||||
import com.android.launcher3.notification.NotificationItemView;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutView;
|
||||
import com.android.launcher3.shortcuts.ShortcutsItemView;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -184,20 +182,20 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
|
||||
orientAboutIcon(originalIcon, arrowHeight + arrowVerticalOffset);
|
||||
}
|
||||
|
||||
ItemInfo originalItemInfo = (ItemInfo) originalIcon.getTag();
|
||||
List<DeepShortcutView> shortcutViews = mShortcutsItemView == null
|
||||
? Collections.EMPTY_LIST
|
||||
: mShortcutsItemView.getDeepShortcutViews(reverseOrder);
|
||||
if (mNotificationItemView != null) {
|
||||
IconPalette iconPalette = originalIcon.getIconPalette();
|
||||
mNotificationItemView.applyColors(iconPalette);
|
||||
BadgeInfo badgeInfo = mLauncher.getPopupDataProvider()
|
||||
.getBadgeInfoForItem(originalItemInfo);
|
||||
updateNotificationHeader(badgeInfo);
|
||||
}
|
||||
|
||||
// Add the arrow.
|
||||
mArrow = addArrowView(arrowHorizontalOffset, arrowVerticalOffset, arrowWidth, arrowHeight);
|
||||
mArrow.setPivotX(arrowWidth / 2);
|
||||
mArrow.setPivotY(mIsAboveIcon ? 0 : arrowHeight);
|
||||
PopupItemView firstItem = getItemViewAt(mIsAboveIcon ? getItemCount() - 1 : 0);
|
||||
mArrow.setBackgroundTintList(firstItem.getAttachedArrowColor());
|
||||
|
||||
animateOpen();
|
||||
|
||||
@@ -208,7 +206,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
|
||||
// Load the shortcuts on a background thread and update the container as it animates.
|
||||
final Looper workerLooper = LauncherModel.getWorkerLooper();
|
||||
new Handler(workerLooper).postAtFrontOfQueue(PopupPopulator.createUpdateRunnable(
|
||||
mLauncher, (ItemInfo) originalIcon.getTag(), new Handler(Looper.getMainLooper()),
|
||||
mLauncher, originalItemInfo, new Handler(Looper.getMainLooper()),
|
||||
this, shortcutIds, shortcutViews, notificationKeys, mNotificationItemView));
|
||||
}
|
||||
|
||||
@@ -540,6 +538,24 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the notification header to reflect the badge info. Since this can be called
|
||||
* for any badge info (not necessarily the one associated with this app), we first
|
||||
* check that the ItemInfo matches the one of this popup.
|
||||
*/
|
||||
public void updateNotificationHeader(BadgeInfo badgeInfo, ItemInfo originalItemInfo) {
|
||||
if (originalItemInfo != mOriginalIcon.getTag()) {
|
||||
return;
|
||||
}
|
||||
updateNotificationHeader(badgeInfo);
|
||||
}
|
||||
|
||||
private void updateNotificationHeader(BadgeInfo badgeInfo) {
|
||||
if (mNotificationItemView != null && badgeInfo != null) {
|
||||
mNotificationItemView.updateHeader(badgeInfo.getNotificationCount());
|
||||
}
|
||||
}
|
||||
|
||||
public void trimNotifications(Map<PackageUserKey, BadgeInfo> updatedBadges) {
|
||||
if (mNotificationItemView == null) {
|
||||
return;
|
||||
@@ -576,8 +592,6 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
|
||||
close(false);
|
||||
return;
|
||||
}
|
||||
View firstItem = getItemViewAt(mIsAboveIcon ? getItemCount() - 1 : 0);
|
||||
mArrow.setBackgroundTintList(firstItem.getBackgroundTintList());
|
||||
}
|
||||
});
|
||||
removeNotification.play(fade);
|
||||
|
||||
@@ -20,7 +20,6 @@ import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
@@ -109,10 +108,6 @@ public abstract class PopupItemView extends FrameLayout
|
||||
canvas.restoreToCount(saveCount);
|
||||
}
|
||||
|
||||
protected ColorStateList getAttachedArrowColor() {
|
||||
return getBackgroundTintList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an animator to play when the shortcut container is being opened.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user