diff options
| -rw-r--r-- | core/java/android/app/Notification.java | 102 | ||||
| -rw-r--r-- | core/res/res/layout/notification_template_header.xml | 12 | ||||
| -rw-r--r-- | core/res/res/layout/notification_template_material_base.xml | 14 | ||||
| -rw-r--r-- | core/res/res/values/dimens.xml | 4 | ||||
| -rw-r--r-- | core/res/res/values/ids.xml | 6 | ||||
| -rw-r--r-- | core/res/res/values/symbols.xml | 4 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java) | 220 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java | 11 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java | 5 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java | 17 |
10 files changed, 271 insertions, 124 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index a886beddf64c..d5572bf130c1 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -30,6 +30,7 @@ import android.annotation.IdRes; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.Px; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -5105,33 +5106,29 @@ public class Notification implements Parcelable if (result == null) { result = new TemplateBindResult(); } - boolean largeIconShown = bindLargeIcon(contentView, p); + final boolean largeIconShown = bindLargeIcon(contentView, p); calculateLargeIconMarginEnd(largeIconShown, result); if (p.mHeaderless) { // views in the headerless (collapsed) state - contentView.setViewLayoutMarginEnd(R.id.notification_standard_view_column, - result.getHeadingExtraMarginEnd()); + result.mHeadingExtraMarginSet.applyToView(contentView, + R.id.notification_headerless_view_column); } else { // views in states with a header (big states) - contentView.setInt(R.id.notification_header, "setTopLineExtraMarginEnd", - result.getHeadingExtraMarginEnd()); - contentView.setViewLayoutMarginEnd(R.id.line1, result.getTitleMarginEnd()); + result.mHeadingExtraMarginSet.applyToView(contentView, R.id.notification_header); + result.mTitleMarginSet.applyToView(contentView, R.id.line1); } } private void calculateLargeIconMarginEnd(boolean largeIconShown, @NonNull TemplateBindResult result) { - int contentMargin = mContext.getResources().getDimensionPixelSize( + final Resources resources = mContext.getResources(); + final int contentMargin = resources.getDimensionPixelOffset( R.dimen.notification_content_margin_end); - int expanderSize = mContext.getResources().getDimensionPixelSize( + final int expanderSize = resources.getDimensionPixelSize( R.dimen.notification_header_expand_icon_size) - contentMargin; - int extraMarginEnd = 0; - if (largeIconShown) { - int iconSize = mContext.getResources().getDimensionPixelSize( - R.dimen.notification_right_icon_size); - extraMarginEnd = iconSize + contentMargin; - } - result.setRightIconState(largeIconShown, extraMarginEnd, expanderSize); + final int extraMarginEndIfVisible = resources.getDimensionPixelSize( + R.dimen.notification_right_icon_size) + contentMargin; + result.setRightIconState(largeIconShown, extraMarginEndIfVisible, expanderSize); } /** @@ -7759,8 +7756,10 @@ public class Notification implements Parcelable addExtras(mBuilder.mN.extras); if (!isConversationLayout) { // also update the end margin if there is an image + // NOTE: This template doesn't support moving this icon to the left, so we don't + // need to fully apply the MarginSet contentView.setViewLayoutMarginEnd(R.id.notification_messaging, - bindResult.getHeadingExtraMarginEnd()); + bindResult.mHeadingExtraMarginSet.getValue()); } contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor", mBuilder.isColorized(p) @@ -8757,9 +8756,8 @@ public class Notification implements Parcelable if (!headerless) { // also update the end margin to account for the large icon or expander Resources resources = mBuilder.mContext.getResources(); - int endMargin = resources.getDimensionPixelSize( - R.dimen.notification_content_margin_end) + result.getTitleMarginEnd(); - remoteViews.setViewLayoutMarginEnd(R.id.notification_main_column, endMargin); + result.mTitleMarginSet.applyToView(remoteViews, R.id.notification_main_column, + resources.getDimensionPixelOffset(R.dimen.notification_content_margin_end)); } } @@ -10997,42 +10995,74 @@ public class Notification implements Parcelable */ private static class TemplateBindResult { boolean mRightIconVisible; - int mRightIconMarginEnd; - int mExpanderSize; /** - * @return the margin end that needs to be added to the heading so that it won't overlap + * The margin end that needs to be added to the heading so that it won't overlap * with the large icon. This value includes the space required to accommodate the large * icon, but should be added to the space needed to accommodate the expander. This does * not include the 16dp content margin that all notification views must have. */ - public int getHeadingExtraMarginEnd() { - return mRightIconMarginEnd; - } + public final MarginSet mHeadingExtraMarginSet = new MarginSet(); /** - * @return the margin end that needs to be added to the heading so that it won't overlap + * The margin end that needs to be added to the heading so that it won't overlap * with the large icon. This value includes the space required to accommodate the large * icon as well as the expander. This does not include the 16dp content margin that all * notification views must have. */ - public int getHeadingFullMarginEnd() { - return mRightIconMarginEnd + mExpanderSize; - } + public final MarginSet mHeadingFullMarginSet = new MarginSet(); /** - * @return the margin end that needs to be added to the title text of the big state + * The margin end that needs to be added to the title text of the big state * so that it won't overlap with the large icon, but assuming the text can run under * the expander when that icon is not visible. */ - public int getTitleMarginEnd() { - return mRightIconVisible ? getHeadingFullMarginEnd() : 0; - } + public final MarginSet mTitleMarginSet = new MarginSet(); - public void setRightIconState(boolean visible, int marginEnd, int expanderSize) { + public void setRightIconState(boolean visible, int marginEndIfVisible, int expanderSize) { mRightIconVisible = visible; - mRightIconMarginEnd = marginEnd; - mExpanderSize = expanderSize; + mHeadingExtraMarginSet.setValues(0, marginEndIfVisible); + mHeadingFullMarginSet.setValues(expanderSize, marginEndIfVisible + expanderSize); + mTitleMarginSet.setValues(0, marginEndIfVisible + expanderSize); + } + + /** + * This contains the end margins for a view when the right icon is visible or not. These + * values are both needed so that NotificationGroupingUtil can 'move' the right_icon to the + * left_icon and adjust the margins, and to undo that change as well. + */ + private class MarginSet { + private int mValueIfGone; + private int mValueIfVisible; + + public void setValues(int valueIfGone, int valueIfVisible) { + mValueIfGone = valueIfGone; + mValueIfVisible = valueIfVisible; + } + + public void applyToView(@NonNull RemoteViews views, @IdRes int viewId) { + applyToView(views, viewId, 0); + } + + public void applyToView(@NonNull RemoteViews views, @IdRes int viewId, + @Px int extraMargin) { + final int marginEnd = getValue() + extraMargin; + if (viewId == R.id.notification_header) { + views.setInt(R.id.notification_header, "setTopLineExtraMarginEnd", marginEnd); + } else { + views.setViewLayoutMarginEnd(viewId, marginEnd); + } + if (mRightIconVisible) { + views.setIntTag(viewId, R.id.tag_margin_end_when_icon_visible, + mValueIfVisible + extraMargin); + views.setIntTag(viewId, R.id.tag_margin_end_when_icon_gone, + mValueIfGone + extraMargin); + } + } + + public int getValue() { + return mRightIconVisible ? mValueIfVisible : mValueIfGone; + } } } diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml index b0ee12a520d9..88998f2167a8 100644 --- a/core/res/res/layout/notification_template_header.xml +++ b/core/res/res/layout/notification_template_header.xml @@ -26,6 +26,18 @@ android:theme="@style/Theme.DeviceDefault.Notification" > + <ImageView + android:id="@+id/left_icon" + android:layout_width="@dimen/notification_left_icon_size" + android:layout_height="@dimen/notification_left_icon_size" + android:layout_gravity="center_vertical|start" + android:layout_marginStart="@dimen/notification_left_icon_start" + android:background="@drawable/notification_large_icon_outline" + android:importantForAccessibility="no" + android:scaleType="centerCrop" + android:visibility="gone" + /> + <com.android.internal.widget.CachingIconView android:id="@+id/icon" android:layout_width="@dimen/notification_icon_circle_size" diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml index 69d4a12f4d69..000638475a10 100644 --- a/core/res/res/layout/notification_template_material_base.xml +++ b/core/res/res/layout/notification_template_material_base.xml @@ -23,6 +23,18 @@ android:tag="base" > + <ImageView + android:id="@+id/left_icon" + android:layout_width="@dimen/notification_left_icon_size" + android:layout_height="@dimen/notification_left_icon_size" + android:layout_gravity="center_vertical|start" + android:layout_marginStart="@dimen/notification_left_icon_start" + android:background="@drawable/notification_large_icon_outline" + android:importantForAccessibility="no" + android:scaleType="centerCrop" + android:visibility="gone" + /> + <com.android.internal.widget.CachingIconView android:id="@+id/icon" android:layout_width="@dimen/notification_icon_circle_size" @@ -34,7 +46,7 @@ /> <LinearLayout - android:id="@+id/notification_standard_view_column" + android:id="@+id/notification_headerless_view_column" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 19591f6a666f..4bcabff109ea 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -714,6 +714,10 @@ <dimen name="notification_right_icon_headerless_margin">12dp</dimen> <!-- The top margin of the right icon in the "big" notification states --> <dimen name="notification_right_icon_big_margin_top">16dp</dimen> + <!-- The size of the left icon --> + <dimen name="notification_left_icon_size">@dimen/notification_icon_circle_size</dimen> + <!-- The left padding of the left icon --> + <dimen name="notification_left_icon_start">@dimen/notification_icon_circle_start</dimen> <!-- The alpha of a disabled notification button --> <item type="dimen" format="float" name="notification_action_disabled_alpha">0.5</item> diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index f77c6f99c063..a12d2a951460 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -194,6 +194,12 @@ <!-- A tag used to save the index where the custom view is stored --> <item type="id" name="notification_custom_view_index_tag" /> + <!-- A tag used to store the margin end for this view when the right icon is visible --> + <item type="id" name="tag_margin_end_when_icon_gone" /> + + <!-- A tag used to store the margin end for this view when the right icon is gone --> + <item type="id" name="tag_margin_end_when_icon_visible" /> + <!-- Marks the "copy to clipboard" button in the ChooserActivity --> <item type="id" name="chooser_copy_button" /> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index e3986fa96fb5..6da7eba62585 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -218,7 +218,7 @@ <java-symbol type="id" name="inbox_text6" /> <java-symbol type="id" name="status_bar_latest_event_content" /> <java-symbol type="id" name="notification_main_column" /> - <java-symbol type="id" name="notification_standard_view_column" /> + <java-symbol type="id" name="notification_headerless_view_column" /> <java-symbol type="id" name="sms_short_code_confirm_message" /> <java-symbol type="id" name="sms_short_code_detail_layout" /> <java-symbol type="id" name="sms_short_code_detail_message" /> @@ -3070,6 +3070,8 @@ <java-symbol type="dimen" name="notification_media_image_margin_end" /> <java-symbol type="id" name="notification_action_list_margin_target" /> <java-symbol type="dimen" name="notification_action_disabled_alpha" /> + <java-symbol type="id" name="tag_margin_end_when_icon_visible" /> + <java-symbol type="id" name="tag_margin_end_when_icon_gone" /> <!-- Override Wake Key Behavior When Screen is Off --> <java-symbol type="bool" name="config_wakeOnDpadKeyPress" /> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java index 84818eea8a23..0e6bcc58b7c0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Android Open Source Project + * Copyright (C) 2020 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. @@ -11,19 +11,22 @@ * 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 + * limitations under the License. */ package com.android.systemui.statusbar; import android.app.Notification; +import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.text.TextUtils; +import android.view.NotificationHeaderView; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.android.internal.R; import com.android.internal.widget.CachingIconView; import com.android.internal.widget.ConversationLayout; import com.android.internal.widget.NotificationExpandButton; @@ -36,35 +39,38 @@ import java.util.List; import java.util.Objects; /** - * A Util to manage {@link android.view.NotificationHeaderView} objects and their redundancies. + * A utility to manage notification views when they are placed in a group by adjusting elements + * to reduce redundancies and occasionally tweak layouts to highlight the unique content. */ -public class NotificationHeaderUtil { - - private static final TextViewComparator sTextViewComparator = new TextViewComparator(); - private static final TextViewComparator sAppNameComparator = new AppNameComparator(); - private static final VisibilityApplicator sVisibilityApplicator = new VisibilityApplicator(); - private static final VisibilityApplicator sAppNameApplicator = new AppNameApplicator(); - private static final DataExtractor sIconExtractor = new DataExtractor() { +public class NotificationGroupingUtil { + + private static final TextViewComparator TEXT_VIEW_COMPARATOR = new TextViewComparator(); + private static final TextViewComparator APP_NAME_COMPARATOR = new AppNameComparator(); + private static final ViewComparator BADGE_COMPARATOR = new BadgeComparator(); + private static final VisibilityApplicator VISIBILITY_APPLICATOR = new VisibilityApplicator(); + private static final VisibilityApplicator APP_NAME_APPLICATOR = new AppNameApplicator(); + private static final ResultApplicator LEFT_ICON_APPLICATOR = new LeftIconApplicator(); + private static final DataExtractor ICON_EXTRACTOR = new DataExtractor() { @Override public Object extractData(ExpandableNotificationRow row) { return row.getEntry().getSbn().getNotification(); } }; - private static final IconComparator sIconVisibilityComparator = new IconComparator() { + private static final IconComparator ICON_VISIBILITY_COMPARATOR = new IconComparator() { public boolean compare(View parent, View child, Object parentData, Object childData) { return hasSameIcon(parentData, childData) && hasSameColor(parentData, childData); } }; - private static final IconComparator sGreyComparator = new IconComparator() { + private static final IconComparator GREY_COMPARATOR = new IconComparator() { public boolean compare(View parent, View child, Object parentData, Object childData) { return !hasSameIcon(parentData, childData) || hasSameColor(parentData, childData); } }; - private final static ResultApplicator mGreyApplicator = new ResultApplicator() { + private static final ResultApplicator GREY_APPLICATOR = new ResultApplicator() { @Override public void apply(View parent, View view, boolean apply, boolean reset) { CachingIconView icon = view.findViewById(com.android.internal.R.id.icon); @@ -80,87 +86,79 @@ public class NotificationHeaderUtil { }; private final ExpandableNotificationRow mRow; - private final ArrayList<HeaderProcessor> mComparators = new ArrayList<>(); + private final ArrayList<Processor> mProcessors = new ArrayList<>(); private final HashSet<Integer> mDividers = new HashSet<>(); - public NotificationHeaderUtil(ExpandableNotificationRow row) { + public NotificationGroupingUtil(ExpandableNotificationRow row) { mRow = row; // To hide the icons if they are the same and the color is the same - mComparators.add(new HeaderProcessor(mRow, + mProcessors.add(new Processor(mRow, com.android.internal.R.id.icon, - sIconExtractor, - sIconVisibilityComparator, - sVisibilityApplicator)); + ICON_EXTRACTOR, + ICON_VISIBILITY_COMPARATOR, + VISIBILITY_APPLICATOR)); // To grey them out the icons and expand button when the icons are not the same - mComparators.add(new HeaderProcessor(mRow, - com.android.internal.R.id.notification_header, - sIconExtractor, - sGreyComparator, - mGreyApplicator)); - mComparators.add(new HeaderProcessor(mRow, + mProcessors.add(new Processor(mRow, + com.android.internal.R.id.status_bar_latest_event_content, + ICON_EXTRACTOR, + GREY_COMPARATOR, + GREY_APPLICATOR)); + mProcessors.add(new Processor(mRow, + com.android.internal.R.id.status_bar_latest_event_content, + ICON_EXTRACTOR, + ICON_VISIBILITY_COMPARATOR, + LEFT_ICON_APPLICATOR)); + mProcessors.add(new Processor(mRow, com.android.internal.R.id.profile_badge, null /* Extractor */, - new ViewComparator() { - @Override - public boolean compare(View parent, View child, Object parentData, - Object childData) { - return parent.getVisibility() != View.GONE; - } - - @Override - public boolean isEmpty(View view) { - if (view instanceof ImageView) { - return ((ImageView) view).getDrawable() == null; - } - return false; - } - }, - sVisibilityApplicator)); - mComparators.add(new HeaderProcessor( - mRow, + BADGE_COMPARATOR, + VISIBILITY_APPLICATOR)); + mProcessors.add(new Processor(mRow, com.android.internal.R.id.app_name_text, null, - sAppNameComparator, - sAppNameApplicator)); - mComparators.add(HeaderProcessor.forTextView(mRow, - com.android.internal.R.id.header_text)); + APP_NAME_COMPARATOR, + APP_NAME_APPLICATOR)); + mProcessors.add(Processor.forTextView(mRow, com.android.internal.R.id.header_text)); mDividers.add(com.android.internal.R.id.header_text_divider); mDividers.add(com.android.internal.R.id.header_text_secondary_divider); mDividers.add(com.android.internal.R.id.time_divider); } - public void updateChildrenHeaderAppearance() { + /** + * Update the appearance of the children in this group to reduce redundancies. + */ + public void updateChildrenAppearance() { List<ExpandableNotificationRow> notificationChildren = mRow.getAttachedChildren(); if (notificationChildren == null) { return; } - // Initialize the comparators - for (int compI = 0; compI < mComparators.size(); compI++) { - mComparators.get(compI).init(); + // Initialize the processors + for (int compI = 0; compI < mProcessors.size(); compI++) { + mProcessors.get(compI).init(); } // Compare all notification headers for (int i = 0; i < notificationChildren.size(); i++) { ExpandableNotificationRow row = notificationChildren.get(i); - for (int compI = 0; compI < mComparators.size(); compI++) { - mComparators.get(compI).compareToHeader(row); + for (int compI = 0; compI < mProcessors.size(); compI++) { + mProcessors.get(compI).compareToGroupParent(row); } } // Apply the comparison to the row for (int i = 0; i < notificationChildren.size(); i++) { ExpandableNotificationRow row = notificationChildren.get(i); - for (int compI = 0; compI < mComparators.size(); compI++) { - mComparators.get(compI).apply(row); + for (int compI = 0; compI < mProcessors.size(); compI++) { + mProcessors.get(compI).apply(row); } // We need to sanitize the dividers since they might be off-balance now - sanitizeHeaderViews(row); + sanitizeTopLineViews(row); } } - private void sanitizeHeaderViews(ExpandableNotificationRow row) { + private void sanitizeTopLineViews(ExpandableNotificationRow row) { if (row.isSummaryWithChildren()) { - sanitizeHeader(row.getNotificationViewWrapper().getNotificationHeader()); + sanitizeTopLine(row.getNotificationViewWrapper().getNotificationHeader()); return; } final NotificationContentView layout = row.getPrivateLayout(); @@ -171,13 +169,11 @@ public class NotificationHeaderUtil { private void sanitizeChild(View child) { if (child != null) { - ViewGroup header = child.findViewById( - com.android.internal.R.id.notification_top_line); - sanitizeHeader(header); + sanitizeTopLine(child.findViewById(R.id.notification_top_line)); } } - private void sanitizeHeader(ViewGroup rowHeader) { + private void sanitizeTopLine(ViewGroup rowHeader) { if (rowHeader == null) { return; } @@ -225,28 +221,31 @@ public class NotificationHeaderUtil { } } - public void restoreNotificationHeader(ExpandableNotificationRow row) { - for (int compI = 0; compI < mComparators.size(); compI++) { - mComparators.get(compI).apply(row, true /* reset */); + /** + * Reset the modifications to this row for removing it from the group. + */ + public void restoreChildNotification(ExpandableNotificationRow row) { + for (int compI = 0; compI < mProcessors.size(); compI++) { + mProcessors.get(compI).apply(row, true /* reset */); } - sanitizeHeaderViews(row); + sanitizeTopLineViews(row); } - private static class HeaderProcessor { + private static class Processor { private final int mId; private final DataExtractor mExtractor; + private final ViewComparator mComparator; private final ResultApplicator mApplicator; private final ExpandableNotificationRow mParentRow; private boolean mApply; private View mParentView; - private ViewComparator mComparator; private Object mParentData; - public static HeaderProcessor forTextView(ExpandableNotificationRow row, int id) { - return new HeaderProcessor(row, id, null, sTextViewComparator, sVisibilityApplicator); + public static Processor forTextView(ExpandableNotificationRow row, int id) { + return new Processor(row, id, null, TEXT_VIEW_COMPARATOR, VISIBILITY_APPLICATOR); } - HeaderProcessor(ExpandableNotificationRow row, int id, DataExtractor extractor, + Processor(ExpandableNotificationRow row, int id, DataExtractor extractor, ViewComparator comparator, ResultApplicator applicator) { mId = id; @@ -262,7 +261,7 @@ public class NotificationHeaderUtil { mParentData = mExtractor == null ? null : mExtractor.extractData(mParentRow); mApply = !mComparator.isEmpty(mParentView); } - public void compareToHeader(ExpandableNotificationRow row) { + public void compareToGroupParent(ExpandableNotificationRow row) { if (!mApply) { return; } @@ -308,8 +307,8 @@ public class NotificationHeaderUtil { private interface ViewComparator { /** - * @param parent the parent view - * @param child the child view + * @param parent the view with the given id in the group header + * @param child the view with the given id in the child notification * @param parentData optional data for the parent * @param childData optional data for the child * @return whether to views are the same @@ -322,6 +321,21 @@ public class NotificationHeaderUtil { Object extractData(ExpandableNotificationRow row); } + private static class BadgeComparator implements ViewComparator { + @Override + public boolean compare(View parent, View child, Object parentData, Object childData) { + return parent.getVisibility() != View.GONE; + } + + @Override + public boolean isEmpty(View view) { + if (view instanceof ImageView) { + return ((ImageView) view).getDrawable() == null; + } + return false; + } + } + private static class TextViewComparator implements ViewComparator { @Override public boolean compare(View parent, View child, Object parentData, Object childData) { @@ -338,7 +352,7 @@ public class NotificationHeaderUtil { } } - private static abstract class IconComparator implements ViewComparator { + private abstract static class IconComparator implements ViewComparator { @Override public boolean compare(View parent, View child, Object parentData, Object childData) { return false; @@ -366,6 +380,12 @@ public class NotificationHeaderUtil { } private interface ResultApplicator { + /** + * @param parent the root view of the child notification + * @param view the view with the given id in the child notification + * @param apply whether the state should be applied or removed + * @param reset if [de]application is the result of a reset + */ void apply(View parent, View view, boolean apply, boolean reset); } @@ -403,4 +423,54 @@ public class NotificationHeaderUtil { return super.compare(parent, child, parentData, childData); } } + + private static class LeftIconApplicator implements ResultApplicator { + + public static final int[] MARGIN_ADJUSTED_VIEWS = { + R.id.notification_headerless_view_column, + R.id.line1, + R.id.notification_main_column, + R.id.notification_header}; + + @Override + public void apply(View parent, View child, boolean apply, boolean reset) { + ImageView rightIcon = child.findViewById(com.android.internal.R.id.right_icon); + ImageView leftIcon = child.findViewById(com.android.internal.R.id.left_icon); + if (rightIcon == null || leftIcon == null) { + return; + } + Drawable iconDrawable = rightIcon.getDrawable(); + if (iconDrawable == null) { + return; + } + rightIcon.setVisibility(apply ? View.GONE : View.VISIBLE); + leftIcon.setVisibility(apply ? View.VISIBLE : View.GONE); + leftIcon.setImageDrawable(apply ? iconDrawable : null); + + for (int viewId : MARGIN_ADJUSTED_VIEWS) { + adjustMargins(!apply, child.findViewById(viewId)); + } + } + + void adjustMargins(boolean iconVisible, View target) { + if (target == null) { + return; + } + Integer value = (Integer) target.getTag(iconVisible + ? com.android.internal.R.id.tag_margin_end_when_icon_visible + : com.android.internal.R.id.tag_margin_end_when_icon_gone); + if (value == null) { + return; + } + if (target instanceof NotificationHeaderView) { + ((NotificationHeaderView) target).setTopLineExtraMarginEnd(value); + } else { + ViewGroup.LayoutParams layoutParams = target.getLayoutParams(); + if (layoutParams instanceof ViewGroup.MarginLayoutParams) { + ((ViewGroup.MarginLayoutParams) layoutParams).setMarginEnd(value); + target.setLayoutParams(layoutParams); + } + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 5ed17f1ee07f..10118e4733ba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -558,7 +558,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView setChronometerRunning(true); } if (mNotificationParent != null) { - mNotificationParent.updateChildrenHeaderAppearance(); + mNotificationParent.updateChildrenAppearance(); } onAttachedChildrenCountChanged(); // The public layouts expand button is always visible @@ -2337,7 +2337,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } getShowingLayout().updateBackgroundColor(false /* animate */); mPrivateLayout.updateExpandButtons(isExpandable()); - updateChildrenHeaderAppearance(); + updateChildrenAppearance(); updateChildrenVisibility(); applyChildrenRoundness(); } @@ -2382,9 +2382,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return channels; } - public void updateChildrenHeaderAppearance() { + /** + * If this is a group, update the appearance of the children. + */ + public void updateChildrenAppearance() { if (mIsSummaryWithChildren) { - mChildrenContainer.updateChildrenHeaderAppearance(); + mChildrenContainer.updateChildrenAppearance(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java index 05db67d706cf..37d5da24a704 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java @@ -64,6 +64,7 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { private ImageView mWorkProfileImage; private View mAudiblyAlertedIcon; private View mFeedbackIcon; + private View mLeftIcon; private View mRightIcon; private boolean mIsLowPriority; @@ -108,6 +109,7 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { mAppNameText = mView.findViewById(com.android.internal.R.id.app_name_text); mExpandButton = mView.findViewById(com.android.internal.R.id.expand_button); mAltExpandTarget = mView.findViewById(com.android.internal.R.id.alternate_expand_target); + mLeftIcon = mView.findViewById(com.android.internal.R.id.left_icon); mRightIcon = mView.findViewById(com.android.internal.R.id.right_icon); mWorkProfileImage = mView.findViewById(com.android.internal.R.id.profile_badge); mNotificationHeader = mView.findViewById(com.android.internal.R.id.notification_header); @@ -146,6 +148,9 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { updateCropToPaddingForImageViews(); Notification notification = row.getEntry().getSbn().getNotification(); mIcon.setTag(ImageTransformState.ICON_TAG, notification.getSmallIcon()); + if (mLeftIcon != null) { + mLeftIcon.setClipToOutline(true); + } if (mRightIcon != null) { mRightIcon.setClipToOutline(true); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index b04f94ce9c1d..601fc197cfa6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java @@ -34,7 +34,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.widget.CachingIconView; import com.android.systemui.R; import com.android.systemui.statusbar.CrossFadeHelper; -import com.android.systemui.statusbar.NotificationHeaderUtil; +import com.android.systemui.statusbar.NotificationGroupingUtil; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -94,7 +94,7 @@ public class NotificationChildrenContainer extends ViewGroup { private NotificationViewWrapper mNotificationHeaderWrapper; private NotificationHeaderView mNotificationHeaderLowPriority; private NotificationViewWrapper mNotificationHeaderWrapperLowPriority; - private NotificationHeaderUtil mHeaderUtil; + private NotificationGroupingUtil mGroupingUtil; private ViewState mHeaderViewState; private int mClipBottomAmount; private boolean mIsLowPriority; @@ -299,7 +299,7 @@ public class NotificationChildrenContainer extends ViewGroup { row.setSystemChildExpanded(false); row.setUserLocked(false); if (!row.isRemoved()) { - mHeaderUtil.restoreNotificationHeader(row); + mGroupingUtil.restoreChildNotification(row); } } @@ -341,7 +341,7 @@ public class NotificationChildrenContainer extends ViewGroup { } recreateLowPriorityHeader(builder, isConversation); updateHeaderVisibility(false /* animate */); - updateChildrenHeaderAppearance(); + updateChildrenAppearance(); } /** @@ -389,8 +389,11 @@ public class NotificationChildrenContainer extends ViewGroup { } } - public void updateChildrenHeaderAppearance() { - mHeaderUtil.updateChildrenHeaderAppearance(); + /** + * Update the appearance of the children to reduce redundancies. + */ + public void updateChildrenAppearance() { + mGroupingUtil.updateChildrenAppearance(); } public void updateGroupOverflow() { @@ -861,7 +864,7 @@ public class NotificationChildrenContainer extends ViewGroup { public void setContainingNotification(ExpandableNotificationRow parent) { mContainingNotification = parent; - mHeaderUtil = new NotificationHeaderUtil(mContainingNotification); + mGroupingUtil = new NotificationGroupingUtil(mContainingNotification); } public ExpandableNotificationRow getContainingNotification() { |