Add importance ring around conversation badge
Bug: 150905003
Test: manual
Change-Id: I967122fcf6404491fb514bc42e5f9e64490b8024
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 1320d1d..b58a85e 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -7584,6 +7584,7 @@
isOneToOne = !isGroupConversation();
}
boolean isConversationLayout = mConversationType != CONVERSATION_TYPE_LEGACY;
+ boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT;
Icon largeIcon = isConversationLayout ? mShortcutIcon : mBuilder.mN.mLargeIcon;
TemplateBindResult bindResult = new TemplateBindResult();
StandardTemplateParams p = mBuilder.mParams.reset()
@@ -7626,6 +7627,10 @@
isOneToOne);
contentView.setCharSequence(R.id.status_bar_latest_event_content,
"setConversationTitle", conversationTitle);
+ if (isConversationLayout) {
+ contentView.setBoolean(R.id.status_bar_latest_event_content,
+ "setIsImportantConversation", isImportantConversation);
+ }
contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon",
largeIcon);
contentView.setBundle(R.id.status_bar_latest_event_content, "setData",
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 4028fda..f9aae0f 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -120,6 +120,7 @@
private int mIconSizeBadged;
private int mIconSizeCentered;
private CachingIconView mIcon;
+ private View mImportanceRingView;
private int mExpandedGroupTopMargin;
private View mConversationFacePile;
private int mNotificationBackgroundColor;
@@ -169,6 +170,7 @@
mTextPaint.setAntiAlias(true);
mConversationIcon = findViewById(R.id.conversation_icon);
mIcon = findViewById(R.id.icon);
+ mImportanceRingView = findViewById(R.id.conversation_icon_badge_ring);
mConversationIconBadge = findViewById(R.id.conversation_icon_badge);
mIcon.setOnVisibilityChangedListener((visibility) -> {
// Always keep the badge visibility in sync with the icon. This is necessary in cases
@@ -213,6 +215,14 @@
}
/**
+ * Sets this conversation as "important", adding some additional UI treatment.
+ */
+ @RemotableViewMethod
+ public void setIsImportantConversation(boolean isImportantConversation) {
+ mImportanceRingView.setVisibility(isImportantConversation ? VISIBLE : GONE);
+ }
+
+ /**
* Set this layout to show the collapsed representation.
*
* @param isCollapsed is it collapsed
@@ -309,14 +319,12 @@
updateTitleAndNamesDisplay();
updateConversationLayout();
-
}
/**
* Update the layout according to the data provided (i.e mIsOneToOne, expanded etc);
*/
private void updateConversationLayout() {
- // TODO: resolve this from shortcuts
// Set avatar and name
CharSequence conversationText = mConversationTitle;
// TODO: display the secondary text somewhere
@@ -463,7 +471,7 @@
int marginTop;
int iconSize;
if (mIsOneToOne || mIsCollapsed) {
- // Baded format
+ // Badged format
gravity = Gravity.LEFT;
marginStart = mBadgedSideMargins;
marginTop = mBadgedSideMargins;
@@ -479,11 +487,9 @@
layoutParams.gravity = gravity;
layoutParams.topMargin = marginTop;
layoutParams.setMarginStart(marginStart);
+ layoutParams.width = iconSize;
+ layoutParams.height = iconSize;
mConversationIconBadge.setLayoutParams(layoutParams);
- ViewGroup.LayoutParams iconParams = mIcon.getLayoutParams();
- iconParams.width = iconSize;
- iconParams.height = iconSize;
- mIcon.setLayoutParams(iconParams);
}
@RemotableViewMethod
diff --git a/core/res/res/drawable/conversation_badge_ring.xml b/core/res/res/drawable/conversation_badge_ring.xml
new file mode 100644
index 0000000..11ba8ad
--- /dev/null
+++ b/core/res/res/drawable/conversation_badge_ring.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+
+ <solid
+ android:color="@color/transparent"/>
+
+ <stroke
+ android:color="@color/conversation_important_highlight"
+ android:width="2dp"/>
+
+ <size
+ android:width="26dp"
+ android:height="26dp"/>
+</shape>
+
diff --git a/core/res/res/layout/notification_template_material_conversation.xml b/core/res/res/layout/notification_template_material_conversation.xml
index 8246583..f79ea62 100644
--- a/core/res/res/layout/notification_template_material_conversation.xml
+++ b/core/res/res/layout/notification_template_material_conversation.xml
@@ -58,18 +58,32 @@
<FrameLayout
android:id="@+id/conversation_icon_badge"
- android:layout_width="20dp"
- android:layout_height="20dp"
+ android:layout_width="@dimen/conversation_icon_size_badged"
+ android:layout_height="@dimen/conversation_icon_size_badged"
android:layout_marginLeft="@dimen/conversation_badge_side_margin"
android:layout_marginTop="@dimen/conversation_badge_side_margin"
- android:background="@drawable/conversation_badge_background" >
+ >
+ <ImageView
+ android:id="@+id/conversation_icon_badge_bg"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:src="@drawable/conversation_badge_background"
+ />
<!-- Badge: 20x20, 48dp padding left + top -->
<com.android.internal.widget.CachingIconView
android:id="@+id/icon"
- android:layout_width="@dimen/conversation_icon_size_badged"
- android:layout_height="@dimen/conversation_icon_size_badged"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="4dp"
android:layout_gravity="center"
/>
+ <ImageView
+ android:id="@+id/conversation_icon_badge_ring"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:src="@drawable/conversation_badge_ring"
+ android:visibility="gone"
+ />
</FrameLayout>
</FrameLayout>
</FrameLayout>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 91248f1..831da6f 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -226,4 +226,6 @@
<color name="resolver_text_color_secondary_dark">#ffC4C6C6</color>
<color name="resolver_empty_state_text">#FF202124</color>
<color name="resolver_empty_state_icon">#FF5F6368</color>
+
+ <color name="conversation_important_highlight">#F9AB00</color>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 6fdc223..abc9692 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -692,10 +692,10 @@
<dimen name="conversation_expand_button_top_margin_expanded">18dp</dimen>
<!-- Side margins of the conversation badge in relation to the conversation icon -->
<dimen name="conversation_badge_side_margin">36dp</dimen>
- <!-- size of the notification icon when badged in a conversation -->
- <dimen name="conversation_icon_size_badged">15dp</dimen>
- <!-- size of the notification icon when centered in a conversation -->
- <dimen name="conversation_icon_size_centered">20dp</dimen>
+ <!-- size of the notification badge when applied to the conversation icon -->
+ <dimen name="conversation_icon_size_badged">20dp</dimen>
+ <!-- size of the notification badge when centered in a conversation -->
+ <dimen name="conversation_icon_size_centered">25dp</dimen>
<!-- margin on the top when the icon is centered for group conversations -->
<dimen name="conversation_icon_margin_top_centered">5dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 103dba4..95fb6857 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3860,6 +3860,8 @@
<java-symbol type="string" name="conversation_title_fallback_group_chat" />
<java-symbol type="id" name="conversation_icon" />
<java-symbol type="id" name="conversation_icon_badge" />
+ <java-symbol type="id" name="conversation_icon_badge_ring" />
+ <java-symbol type="id" name="conversation_icon_badge_bg" />
<java-symbol type="id" name="expand_button_container" />
<java-symbol type="id" name="messaging_group_content_container" />
<java-symbol type="id" name="expand_button_and_content_container" />
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
index 2a45bc2..83e51cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
@@ -49,6 +49,14 @@
mTransformedViews.put(key, transformedView);
}
+ public void addTransformedView(View transformedView) {
+ int key = transformedView.getId();
+ if (key == View.NO_ID) {
+ throw new IllegalArgumentException("View argument does not have a valid id");
+ }
+ addTransformedView(key, transformedView);
+ }
+
/**
* Add a view that transforms to a similar sibling, meaning that we should consider any mapping
* found treated as the same viewType. This is useful for imageViews, where it's hard to compare
@@ -62,6 +70,14 @@
mKeysTransformingToSimilar.add(key);
}
+ public void addViewTransformingToSimilar(View transformedView) {
+ int key = transformedView.getId();
+ if (key == View.NO_ID) {
+ throw new IllegalArgumentException("View argument does not have a valid id");
+ }
+ addViewTransformingToSimilar(key, transformedView);
+ }
+
public void reset() {
mTransformedViews.clear();
mKeysTransformingToSimilar.clear();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
index 8b6081e..53b00f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
@@ -30,41 +30,50 @@
import com.android.systemui.statusbar.notification.row.HybridNotificationView
/**
- * Wraps a notification containing a converation template
+ * Wraps a notification containing a conversation template
*/
class NotificationConversationTemplateViewWrapper constructor(
ctx: Context,
view: View,
row: ExpandableNotificationRow
-)
- : NotificationTemplateViewWrapper(ctx, view, row) {
+) : NotificationTemplateViewWrapper(ctx, view, row) {
- private val minHeightWithActions: Int
- private val conversationLayout: ConversationLayout
- private var conversationIcon: View? = null
- private var conversationBadge: View? = null
- private var expandButton: View? = null
+ private val minHeightWithActions: Int = NotificationUtils.getFontScaledHeight(
+ ctx,
+ R.dimen.notification_messaging_actions_min_height
+ )
+ private val conversationLayout: ConversationLayout = view as ConversationLayout
+
+ private lateinit var conversationIcon: View
+ private lateinit var conversationBadge: View
+ private lateinit var conversationBadgeBg: View
+ private lateinit var expandButton: View
private lateinit var expandButtonContainer: View
private lateinit var imageMessageContainer: ViewGroup
- private var messagingLinearLayout: MessagingLinearLayout? = null
-
- init {
- conversationLayout = view as ConversationLayout
- minHeightWithActions = NotificationUtils.getFontScaledHeight(ctx,
- R.dimen.notification_messaging_actions_min_height)
- }
+ private lateinit var messagingLinearLayout: MessagingLinearLayout
+ private lateinit var importanceRing: View
private fun resolveViews() {
messagingLinearLayout = conversationLayout.messagingLinearLayout
imageMessageContainer = conversationLayout.imageMessageContainer
conversationIcon = conversationLayout.requireViewById(
- com.android.internal.R.id.conversation_icon)
+ com.android.internal.R.id.conversation_icon
+ )
conversationBadge = conversationLayout.requireViewById(
- com.android.internal.R.id.conversation_icon_badge)
+ com.android.internal.R.id.conversation_icon_badge
+ )
+ conversationBadgeBg = conversationLayout.requireViewById(
+ com.android.internal.R.id.conversation_icon_badge_bg
+ )
expandButton = conversationLayout.requireViewById(
- com.android.internal.R.id.expand_button)
+ com.android.internal.R.id.expand_button
+ )
expandButtonContainer = conversationLayout.requireViewById(
- com.android.internal.R.id.expand_button_container)
+ com.android.internal.R.id.expand_button_container
+ )
+ importanceRing = conversationLayout.requireViewById(
+ com.android.internal.R.id.conversation_icon_badge_ring
+ )
}
override fun onContentUpdated(row: ExpandableNotificationRow) {
@@ -77,71 +86,67 @@
override fun updateTransformedTypes() {
// This also clears the existing types
super.updateTransformedTypes()
- messagingLinearLayout?.let {
- mTransformationHelper.addTransformedView(it.id, it)
- }
+
+ addTransformedViews(messagingLinearLayout)
// Let's ignore the image message container since that is transforming as part of the
// messages already
mTransformationHelper.setCustomTransformation(
object : ViewTransformationHelper.CustomTransformation() {
- override fun transformTo(ownState: TransformState,
- otherView: TransformableView,
- transformationAmount: Float): Boolean {
- if (otherView is HybridNotificationView) {
- return false
- }
- // we're hidden by default by the transformState
- ownState.ensureVisible();
- // Let's do nothing otherwise, this is already handled by the messages
- return true
- }
+ override fun transformTo(
+ ownState: TransformState,
+ otherView: TransformableView,
+ transformationAmount: Float
+ ): Boolean {
+ if (otherView is HybridNotificationView) {
+ return false
+ }
+ // we're hidden by default by the transformState
+ ownState.ensureVisible()
+ // Let's do nothing otherwise, this is already handled by the messages
+ return true
+ }
- override fun transformFrom(ownState: TransformState,
- otherView: TransformableView,
- transformationAmount: Float): Boolean {
- if (otherView is HybridNotificationView) {
- return false
- }
- // we're hidden by default by the transformState
- ownState.ensureVisible();
- // Let's do nothing otherwise, this is already handled by the messages
- return true
- }
- }, imageMessageContainer.id)
+ override fun transformFrom(
+ ownState: TransformState,
+ otherView: TransformableView,
+ transformationAmount: Float
+ ): Boolean =
+ transformTo(ownState, otherView, transformationAmount)
+ },
+ imageMessageContainer.id
+ )
- conversationIcon?.let {
- mTransformationHelper.addViewTransformingToSimilar(it.id, it)
- }
- conversationBadge?.let {
- mTransformationHelper.addViewTransformingToSimilar(it.id, it)
- }
- expandButton?.let {
- mTransformationHelper.addViewTransformingToSimilar(it.id, it)
- }
+ addViewsTransformingToSimilar(
+ conversationIcon,
+ conversationBadge,
+ conversationBadgeBg,
+ expandButton,
+ importanceRing
+ )
}
- override fun setRemoteInputVisible(visible: Boolean) {
- conversationLayout.showHistoricMessages(visible)
- }
+ override fun setRemoteInputVisible(visible: Boolean) =
+ conversationLayout.showHistoricMessages(visible)
- override fun updateExpandability(expandable: Boolean, onClickListener: View.OnClickListener?) {
- conversationLayout.updateExpandability(expandable, onClickListener)
- }
+ override fun updateExpandability(expandable: Boolean, onClickListener: View.OnClickListener?) =
+ conversationLayout.updateExpandability(expandable, onClickListener)
override fun disallowSingleClick(x: Float, y: Float): Boolean {
- if (expandButtonContainer.visibility == View.VISIBLE
- && isOnView(expandButtonContainer, x, y)) {
- return true
- }
- return super.disallowSingleClick(x, y)
+ val isOnExpandButton = expandButtonContainer.visibility == View.VISIBLE &&
+ isOnView(expandButtonContainer, x, y)
+ return isOnExpandButton || super.disallowSingleClick(x, y)
}
- override fun getMinLayoutHeight(): Int {
- if (mActionsContainer != null && mActionsContainer.visibility != View.GONE) {
- return minHeightWithActions
- } else {
- return super.getMinLayoutHeight()
- }
- }
+ override fun getMinLayoutHeight(): Int =
+ if (mActionsContainer != null && mActionsContainer.visibility != View.GONE)
+ minHeightWithActions
+ else
+ super.getMinLayoutHeight()
+
+ private fun addTransformedViews(vararg vs: View) =
+ vs.forEach(mTransformationHelper::addTransformedView)
+
+ private fun addViewsTransformingToSimilar(vararg vs: View) =
+ vs.forEach(mTransformationHelper::addViewTransformingToSimilar)
}