Merge changes Ie5bfc2f6,I38e7dc8c,I9308a15a into rvc-dev am: 4605ca9daa
Change-Id: Iec1ed644cfa579275e72d4c7d8578097f1aa0270
This commit is contained in:
@@ -1232,6 +1232,10 @@ public class Notification implements Parcelable
|
||||
/** @hide */
|
||||
public static final String EXTRA_CONVERSATION_ICON = "android.conversationIcon";
|
||||
|
||||
/** @hide */
|
||||
public static final String EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT =
|
||||
"android.conversationUnreadMessageCount";
|
||||
|
||||
/**
|
||||
* {@link #extras} key: an array of {@link android.app.Notification.MessagingStyle.Message}
|
||||
* bundles provided by a
|
||||
@@ -7102,6 +7106,7 @@ public class Notification implements Parcelable
|
||||
List<Message> mHistoricMessages = new ArrayList<>();
|
||||
boolean mIsGroupConversation;
|
||||
@ConversationType int mConversationType = CONVERSATION_TYPE_LEGACY;
|
||||
int mUnreadMessageCount;
|
||||
|
||||
MessagingStyle() {
|
||||
}
|
||||
@@ -7247,6 +7252,17 @@ public class Notification implements Parcelable
|
||||
return mConversationType;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public int getUnreadMessageCount() {
|
||||
return mUnreadMessageCount;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public MessagingStyle setUnreadMessageCount(int unreadMessageCount) {
|
||||
mUnreadMessageCount = unreadMessageCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a message for display by this notification. Convenience call for a simple
|
||||
* {@link Message} in {@link #addMessage(Notification.MessagingStyle.Message)}.
|
||||
@@ -7401,6 +7417,7 @@ public class Notification implements Parcelable
|
||||
if (mShortcutIcon != null) {
|
||||
extras.putParcelable(EXTRA_CONVERSATION_ICON, mShortcutIcon);
|
||||
}
|
||||
extras.putInt(EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT, mUnreadMessageCount);
|
||||
|
||||
fixTitleAndTextExtras(extras);
|
||||
extras.putBoolean(EXTRA_IS_GROUP_CONVERSATION, mIsGroupConversation);
|
||||
@@ -7452,6 +7469,7 @@ public class Notification implements Parcelable
|
||||
Parcelable[] histMessages = extras.getParcelableArray(EXTRA_HISTORIC_MESSAGES);
|
||||
mHistoricMessages = Message.getMessagesFromBundleArray(histMessages);
|
||||
mIsGroupConversation = extras.getBoolean(EXTRA_IS_GROUP_CONVERSATION);
|
||||
mUnreadMessageCount = extras.getInt(EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7601,6 +7619,7 @@ public class Notification implements Parcelable
|
||||
: mBuilder.getMessagingLayoutResource(),
|
||||
p,
|
||||
bindResult);
|
||||
|
||||
addExtras(mBuilder.mN.extras);
|
||||
if (!isConversationLayout) {
|
||||
// also update the end margin if there is an image
|
||||
|
||||
@@ -62,6 +62,7 @@ import com.android.internal.util.ContrastColorUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -151,6 +152,7 @@ public class ConversationLayout extends FrameLayout
|
||||
private int mFacePileProtectionWidth;
|
||||
private int mFacePileProtectionWidthExpanded;
|
||||
private boolean mImportantConversation;
|
||||
private TextView mUnreadBadge;
|
||||
|
||||
public ConversationLayout(@NonNull Context context) {
|
||||
super(context);
|
||||
@@ -277,6 +279,7 @@ public class ConversationLayout extends FrameLayout
|
||||
mAppName.setOnVisibilityChangedListener((visibility) -> {
|
||||
onAppNameVisibilityChanged();
|
||||
});
|
||||
mUnreadBadge = findViewById(R.id.conversation_unread_count);
|
||||
mConversationContentStart = getResources().getDimensionPixelSize(
|
||||
R.dimen.conversation_content_start);
|
||||
mInternalButtonPadding
|
||||
@@ -354,7 +357,6 @@ public class ConversationLayout extends FrameLayout
|
||||
// mUser now set (would be nice to avoid the side effect but WHATEVER)
|
||||
setUser(extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON));
|
||||
|
||||
|
||||
// Append remote input history to newMessages (again, side effect is lame but WHATEVS)
|
||||
RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[])
|
||||
extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
|
||||
@@ -362,9 +364,11 @@ public class ConversationLayout extends FrameLayout
|
||||
|
||||
boolean showSpinner =
|
||||
extras.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false);
|
||||
|
||||
// bind it, baby
|
||||
bind(newMessages, newHistoricMessages, showSpinner);
|
||||
|
||||
int unreadCount = extras.getInt(Notification.EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT);
|
||||
setUnreadCount(unreadCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -372,6 +376,18 @@ public class ConversationLayout extends FrameLayout
|
||||
mImageResolver = resolver;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setUnreadCount(int unreadCount) {
|
||||
mUnreadBadge.setVisibility(mIsCollapsed && unreadCount > 1 ? VISIBLE : GONE);
|
||||
CharSequence text = unreadCount >= 100
|
||||
? getResources().getString(R.string.unread_convo_overflow, 99)
|
||||
: String.format(Locale.getDefault(), "%d", unreadCount);
|
||||
mUnreadBadge.setText(text);
|
||||
mUnreadBadge.setBackgroundTintList(ColorStateList.valueOf(mLayoutColor));
|
||||
boolean needDarkText = ColorUtils.calculateLuminance(mLayoutColor) > 0.5f;
|
||||
mUnreadBadge.setTextColor(needDarkText ? Color.BLACK : Color.WHITE);
|
||||
}
|
||||
|
||||
private void addRemoteInputHistoryToMessages(
|
||||
List<Notification.MessagingStyle.Message> newMessages,
|
||||
RemoteInputHistoryItem[] remoteInputHistory) {
|
||||
|
||||
19
core/res/res/drawable/conversation_unread_bg.xml
Normal file
19
core/res/res/drawable/conversation_unread_bg.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<!--
|
||||
~ 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">
|
||||
<corners android:radius="20sp" />
|
||||
<solid android:color="@android:color/white" />
|
||||
</shape>
|
||||
@@ -199,10 +199,8 @@
|
||||
android:clipChildren="false"
|
||||
/>
|
||||
</com.android.internal.widget.RemeasuringLinearLayout>
|
||||
<!-- Unread Count -->
|
||||
<!-- <TextView /> -->
|
||||
|
||||
<!-- This is where the expand button will be placed when collapsed-->
|
||||
<!-- This is where the expand button container will be placed when collapsed-->
|
||||
</com.android.internal.widget.RemeasuringLinearLayout>
|
||||
|
||||
<include layout="@layout/notification_template_smart_reply_container"
|
||||
@@ -238,6 +236,21 @@
|
||||
android:clipToPadding="false"
|
||||
android:clipChildren="false"
|
||||
/>
|
||||
<!-- Unread Count -->
|
||||
<TextView
|
||||
android:id="@+id/conversation_unread_count"
|
||||
android:layout_width="33sp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="11dp"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:padding="2dp"
|
||||
android:visibility="gone"
|
||||
android:textAppearance="@style/TextAppearance.DeviceDefault.Notification"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="12sp"
|
||||
android:background="@drawable/conversation_unread_bg"
|
||||
/>
|
||||
<com.android.internal.widget.NotificationExpandButton
|
||||
android:id="@+id/expand_button"
|
||||
android:layout_width="@dimen/notification_header_expand_icon_size"
|
||||
@@ -246,6 +259,6 @@
|
||||
android:drawable="@drawable/ic_expand_notification"
|
||||
android:clickable="false"
|
||||
android:importantForAccessibility="no"
|
||||
/>
|
||||
/>
|
||||
</LinearLayout>
|
||||
</com.android.internal.widget.ConversationLayout>
|
||||
|
||||
@@ -5442,6 +5442,9 @@
|
||||
<!-- Conversation Title fallback if the there is no name provided in a group chat conversation [CHAR LIMIT=40]-->
|
||||
<string name="conversation_title_fallback_group_chat">Group Conversation</string>
|
||||
|
||||
<!-- Number of unread messages displayed on a conversation notification, when greater-than-or-equal-to 100 [CHAR LIMIT=3]-->
|
||||
<string name="unread_convo_overflow"><xliff:g id="max_unread_count" example="99">%1$d</xliff:g>+</string>
|
||||
|
||||
<!-- ResolverActivity - profile tabs -->
|
||||
<!-- Label of a tab on a screen. A user can tap this tap to switch to the 'Personal' view (that shows their personal content) if they have a work profile on their device. [CHAR LIMIT=NONE] -->
|
||||
<string name="resolver_personal_tab">Personal</string>
|
||||
|
||||
@@ -3898,6 +3898,8 @@
|
||||
<java-symbol type="dimen" name="button_padding_horizontal_material" />
|
||||
<java-symbol type="dimen" name="button_inset_horizontal_material" />
|
||||
<java-symbol type="layout" name="conversation_face_pile_layout" />
|
||||
<java-symbol type="id" name="conversation_unread_count" />
|
||||
<java-symbol type="string" name="unread_convo_overflow" />
|
||||
|
||||
<!-- Intent resolver and share sheet -->
|
||||
<java-symbol type="string" name="resolver_personal_tab" />
|
||||
|
||||
@@ -38,10 +38,12 @@ public class NotificationUiAdjustment {
|
||||
public final String key;
|
||||
public final List<Notification.Action> smartActions;
|
||||
public final List<CharSequence> smartReplies;
|
||||
public final boolean isConversation;
|
||||
|
||||
@VisibleForTesting
|
||||
NotificationUiAdjustment(
|
||||
String key, List<Notification.Action> smartActions, List<CharSequence> smartReplies) {
|
||||
String key, List<Notification.Action> smartActions, List<CharSequence> smartReplies,
|
||||
boolean isConversation) {
|
||||
this.key = key;
|
||||
this.smartActions = smartActions == null
|
||||
? Collections.emptyList()
|
||||
@@ -49,12 +51,14 @@ public class NotificationUiAdjustment {
|
||||
this.smartReplies = smartReplies == null
|
||||
? Collections.emptyList()
|
||||
: smartReplies;
|
||||
this.isConversation = isConversation;
|
||||
}
|
||||
|
||||
public static NotificationUiAdjustment extractFromNotificationEntry(
|
||||
NotificationEntry entry) {
|
||||
return new NotificationUiAdjustment(
|
||||
entry.getKey(), entry.getSmartActions(), entry.getSmartReplies());
|
||||
entry.getKey(), entry.getSmartActions(), entry.getSmartReplies(),
|
||||
entry.getRanking().isConversation());
|
||||
}
|
||||
|
||||
public static boolean needReinflate(
|
||||
@@ -63,6 +67,9 @@ public class NotificationUiAdjustment {
|
||||
if (oldAdjustment == newAdjustment) {
|
||||
return false;
|
||||
}
|
||||
if (oldAdjustment.isConversation != newAdjustment.isConversation) {
|
||||
return true;
|
||||
}
|
||||
if (areDifferent(oldAdjustment.smartActions, newAdjustment.smartActions)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.notification
|
||||
|
||||
import android.app.Notification
|
||||
import android.content.pm.LauncherApps
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry
|
||||
import javax.inject.Inject
|
||||
|
||||
class ConversationNotificationProcessor @Inject constructor(
|
||||
private val launcherApps: LauncherApps
|
||||
) {
|
||||
fun processNotification(entry: NotificationEntry, recoveredBuilder: Notification.Builder) {
|
||||
val messagingStyle = recoveredBuilder.style as? Notification.MessagingStyle ?: return
|
||||
messagingStyle.conversationType =
|
||||
if (entry.ranking.channel.isImportantConversation)
|
||||
Notification.MessagingStyle.CONVERSATION_TYPE_IMPORTANT
|
||||
else
|
||||
Notification.MessagingStyle.CONVERSATION_TYPE_NORMAL
|
||||
entry.ranking.shortcutInfo?.let { shortcutInfo ->
|
||||
messagingStyle.shortcutIcon = launcherApps.getShortcutIcon(shortcutInfo)
|
||||
shortcutInfo.shortLabel?.let { shortLabel ->
|
||||
messagingStyle.conversationTitle = shortLabel
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.notification
|
||||
|
||||
import android.app.Notification
|
||||
import android.content.Context
|
||||
import android.content.pm.LauncherApps
|
||||
import android.service.notification.NotificationListenerService.Ranking
|
||||
import android.service.notification.NotificationListenerService.RankingMap
|
||||
import com.android.internal.statusbar.NotificationVisibility
|
||||
import com.android.internal.widget.ConversationLayout
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
|
||||
import com.android.systemui.statusbar.notification.row.NotificationContentView
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/** Populates additional information in conversation notifications */
|
||||
class ConversationNotificationProcessor @Inject constructor(
|
||||
private val launcherApps: LauncherApps,
|
||||
private val conversationNotificationManager: ConversationNotificationManager
|
||||
) {
|
||||
fun processNotification(entry: NotificationEntry, recoveredBuilder: Notification.Builder) {
|
||||
val messagingStyle = recoveredBuilder.style as? Notification.MessagingStyle ?: return
|
||||
messagingStyle.conversationType =
|
||||
if (entry.ranking.channel.isImportantConversation)
|
||||
Notification.MessagingStyle.CONVERSATION_TYPE_IMPORTANT
|
||||
else
|
||||
Notification.MessagingStyle.CONVERSATION_TYPE_NORMAL
|
||||
entry.ranking.shortcutInfo?.let { shortcutInfo ->
|
||||
messagingStyle.shortcutIcon = launcherApps.getShortcutIcon(shortcutInfo)
|
||||
shortcutInfo.shortLabel?.let { shortLabel ->
|
||||
messagingStyle.conversationTitle = shortLabel
|
||||
}
|
||||
}
|
||||
messagingStyle.unreadMessageCount =
|
||||
conversationNotificationManager.getUnreadCount(entry, recoveredBuilder)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks state related to conversation notifications, and updates the UI of existing notifications
|
||||
* when necessary.
|
||||
*/
|
||||
@Singleton
|
||||
class ConversationNotificationManager @Inject constructor(
|
||||
private val notificationEntryManager: NotificationEntryManager,
|
||||
private val context: Context
|
||||
) {
|
||||
// Need this state to be thread safe, since it's accessed from the ui thread
|
||||
// (NotificationEntryListener) and a bg thread (NotificationContentInflater)
|
||||
private val states = ConcurrentHashMap<String, ConversationState>()
|
||||
|
||||
private var notifPanelCollapsed = true
|
||||
|
||||
init {
|
||||
notificationEntryManager.addNotificationEntryListener(object : NotificationEntryListener {
|
||||
|
||||
override fun onNotificationRankingUpdated(rankingMap: RankingMap) {
|
||||
fun getLayouts(view: NotificationContentView) =
|
||||
sequenceOf(view.contractedChild, view.expandedChild, view.headsUpChild)
|
||||
val ranking = Ranking()
|
||||
states.keys.asSequence()
|
||||
.mapNotNull { notificationEntryManager.getActiveNotificationUnfiltered(it) }
|
||||
.forEach { entry ->
|
||||
if (rankingMap.getRanking(entry.sbn.key, ranking) &&
|
||||
ranking.isConversation) {
|
||||
val important = ranking.channel.isImportantConversation
|
||||
entry.row?.layouts?.asSequence()
|
||||
?.flatMap(::getLayouts)
|
||||
?.mapNotNull { it as? ConversationLayout }
|
||||
?.forEach { it.setIsImportantConversation(important) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onEntryInflated(entry: NotificationEntry) {
|
||||
if (!entry.ranking.isConversation) return
|
||||
fun updateCount(isExpanded: Boolean) {
|
||||
if (isExpanded && !notifPanelCollapsed) {
|
||||
resetCount(entry.key)
|
||||
entry.row?.let(::resetBadgeUi)
|
||||
}
|
||||
}
|
||||
entry.row?.setOnExpansionChangedListener(::updateCount)
|
||||
updateCount(entry.row?.isExpanded == true)
|
||||
}
|
||||
|
||||
override fun onEntryReinflated(entry: NotificationEntry) = onEntryInflated(entry)
|
||||
|
||||
override fun onEntryRemoved(
|
||||
entry: NotificationEntry,
|
||||
visibility: NotificationVisibility?,
|
||||
removedByUser: Boolean,
|
||||
reason: Int
|
||||
) = removeTrackedEntry(entry)
|
||||
})
|
||||
}
|
||||
|
||||
fun getUnreadCount(entry: NotificationEntry, recoveredBuilder: Notification.Builder): Int =
|
||||
states.compute(entry.key) { _, state ->
|
||||
val newCount = state?.run {
|
||||
val old = Notification.Builder.recoverBuilder(context, notification)
|
||||
val increment = Notification
|
||||
.areStyledNotificationsVisiblyDifferent(old, recoveredBuilder)
|
||||
if (increment) unreadCount + 1 else unreadCount
|
||||
} ?: 1
|
||||
ConversationState(newCount, entry.sbn.notification)
|
||||
}!!.unreadCount
|
||||
|
||||
fun onNotificationPanelExpandStateChanged(isCollapsed: Boolean) {
|
||||
notifPanelCollapsed = isCollapsed
|
||||
if (isCollapsed) return
|
||||
|
||||
// When the notification panel is expanded, reset the counters of any expanded
|
||||
// conversations
|
||||
val expanded = states
|
||||
.asSequence()
|
||||
.mapNotNull { (key, _) ->
|
||||
notificationEntryManager.getActiveNotificationUnfiltered(key)
|
||||
?.let { entry ->
|
||||
if (entry.row?.isExpanded == true) key to entry
|
||||
else null
|
||||
}
|
||||
}
|
||||
.toMap()
|
||||
states.replaceAll { key, state ->
|
||||
if (expanded.contains(key)) state.copy(unreadCount = 0)
|
||||
else state
|
||||
}
|
||||
// Update UI separate from the replaceAll call, since ConcurrentHashMap may re-run the
|
||||
// lambda if threads are in contention.
|
||||
expanded.values.asSequence().mapNotNull { it.row }.forEach(::resetBadgeUi)
|
||||
}
|
||||
|
||||
private fun resetCount(key: String) {
|
||||
states.compute(key) { _, state -> state?.copy(unreadCount = 0) }
|
||||
}
|
||||
|
||||
private fun removeTrackedEntry(entry: NotificationEntry) {
|
||||
states.remove(entry.key)
|
||||
}
|
||||
|
||||
private fun resetBadgeUi(row: ExpandableNotificationRow): Unit =
|
||||
(row.layouts?.asSequence() ?: emptySequence())
|
||||
.mapNotNull { layout -> layout.contractedChild as? ConversationLayout }
|
||||
.forEach { convoLayout -> convoLayout.setUnreadCount(0) }
|
||||
|
||||
private data class ConversationState(val unreadCount: Int, val notification: Notification)
|
||||
}
|
||||
@@ -107,6 +107,7 @@ import com.android.systemui.statusbar.policy.InflatedSmartReplies.SmartRepliesAn
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BooleanSupplier;
|
||||
@@ -136,7 +137,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
*/
|
||||
public interface LayoutListener {
|
||||
void onLayout();
|
||||
}
|
||||
|
||||
/** Listens for changes to the expansion state of this row. */
|
||||
public interface OnExpansionChangedListener {
|
||||
void onExpansionChanged(boolean isExpanded);
|
||||
}
|
||||
|
||||
private StatusBarStateController mStatusbarStateController;
|
||||
@@ -323,6 +328,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
private boolean mWasChildInGroupWhenRemoved;
|
||||
private NotificationInlineImageResolver mImageResolver;
|
||||
private NotificationMediaManager mMediaManager;
|
||||
@Nullable private OnExpansionChangedListener mExpansionChangedListener;
|
||||
|
||||
private SystemNotificationAsyncTask mSystemNotificationAsyncTask =
|
||||
new SystemNotificationAsyncTask();
|
||||
@@ -351,6 +357,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
return isSystemNotification;
|
||||
}
|
||||
|
||||
public NotificationContentView[] getLayouts() {
|
||||
return Arrays.copyOf(mLayouts, mLayouts.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGroupExpansionChanging() {
|
||||
if (isChildInGroup()) {
|
||||
@@ -2911,9 +2921,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
if (mIsSummaryWithChildren) {
|
||||
mChildrenContainer.onExpansionChanged();
|
||||
}
|
||||
if (mExpansionChangedListener != null) {
|
||||
mExpansionChangedListener.onExpansionChanged(nowExpanded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnExpansionChangedListener(@Nullable OnExpansionChangedListener listener) {
|
||||
mExpansionChangedListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
|
||||
super.onInitializeAccessibilityNodeInfoInternal(info);
|
||||
|
||||
@@ -86,6 +86,7 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController;
|
||||
import com.android.systemui.statusbar.VibratorHelper;
|
||||
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
|
||||
import com.android.systemui.statusbar.notification.AnimatableProperty;
|
||||
import com.android.systemui.statusbar.notification.ConversationNotificationManager;
|
||||
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
|
||||
@@ -238,6 +239,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
private final PulseExpansionHandler mPulseExpansionHandler;
|
||||
private final KeyguardBypassController mKeyguardBypassController;
|
||||
private final KeyguardUpdateMonitor mUpdateMonitor;
|
||||
private final ConversationNotificationManager mConversationNotificationManager;
|
||||
|
||||
private KeyguardAffordanceHelper mAffordanceHelper;
|
||||
private KeyguardUserSwitcher mKeyguardUserSwitcher;
|
||||
@@ -451,7 +453,8 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
ActivityManager activityManager, ZenModeController zenModeController,
|
||||
ConfigurationController configurationController,
|
||||
FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
|
||||
StatusBarTouchableRegionManager statusBarTouchableRegionManager) {
|
||||
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
|
||||
ConversationNotificationManager conversationNotificationManager) {
|
||||
super(view, falsingManager, dozeLog, keyguardStateController,
|
||||
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
|
||||
latencyTracker, flingAnimationUtilsBuilder, statusBarTouchableRegionManager);
|
||||
@@ -509,6 +512,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
mShadeController = shadeController;
|
||||
mLockscreenUserManager = notificationLockscreenUserManager;
|
||||
mEntryManager = notificationEntryManager;
|
||||
mConversationNotificationManager = conversationNotificationManager;
|
||||
|
||||
mView.setBackgroundColor(Color.TRANSPARENT);
|
||||
OnAttachStateChangeListener onAttachStateChangeListener = new OnAttachStateChangeListener();
|
||||
@@ -2143,6 +2147,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
super.onExpandingFinished();
|
||||
mNotificationStackScroller.onExpansionStopped();
|
||||
mHeadsUpManager.onExpandingFinished();
|
||||
mConversationNotificationManager.onNotificationPanelExpandStateChanged(isFullyCollapsed());
|
||||
mIsExpanding = false;
|
||||
if (isFullyCollapsed()) {
|
||||
DejankUtils.postAfterTraversal(new Runnable() {
|
||||
|
||||
@@ -188,6 +188,30 @@ public class NotificationUiAdjustmentTest extends SysuiTestCase {
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void needReinflate_bothConversation() {
|
||||
assertThat(NotificationUiAdjustment.needReinflate(
|
||||
createUiAdjustmentForConversation("first", true),
|
||||
createUiAdjustmentForConversation("first", true)))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void needReinflate_neitherConversation() {
|
||||
assertThat(NotificationUiAdjustment.needReinflate(
|
||||
createUiAdjustmentForConversation("first", false),
|
||||
createUiAdjustmentForConversation("first", false)))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void needReinflate_differentIsConversation() {
|
||||
assertThat(NotificationUiAdjustment.needReinflate(
|
||||
createUiAdjustmentForConversation("first", false),
|
||||
createUiAdjustmentForConversation("first", true)))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
private Notification.Action.Builder createActionBuilder(
|
||||
String title, int drawableRes, PendingIntent pendingIntent) {
|
||||
return new Notification.Action.Builder(
|
||||
@@ -200,11 +224,16 @@ public class NotificationUiAdjustmentTest extends SysuiTestCase {
|
||||
|
||||
private NotificationUiAdjustment createUiAdjustmentFromSmartActions(
|
||||
String key, List<Notification.Action> actions) {
|
||||
return new NotificationUiAdjustment(key, actions, null);
|
||||
return new NotificationUiAdjustment(key, actions, null, false);
|
||||
}
|
||||
|
||||
private NotificationUiAdjustment createUiAdjustmentFromSmartReplies(
|
||||
String key, CharSequence[] replies) {
|
||||
return new NotificationUiAdjustment(key, null, Arrays.asList(replies));
|
||||
return new NotificationUiAdjustment(key, null, Arrays.asList(replies), false);
|
||||
}
|
||||
|
||||
private NotificationUiAdjustment createUiAdjustmentForConversation(
|
||||
String key, boolean isConversation) {
|
||||
return new NotificationUiAdjustment(key, null, null, isConversation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ import com.android.systemui.statusbar.PulseExpansionHandler;
|
||||
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
|
||||
import com.android.systemui.statusbar.SysuiStatusBarStateController;
|
||||
import com.android.systemui.statusbar.VibratorHelper;
|
||||
import com.android.systemui.statusbar.notification.ConversationNotificationManager;
|
||||
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
|
||||
@@ -169,6 +170,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
private ZenModeController mZenModeController;
|
||||
@Mock
|
||||
private ConfigurationController mConfigurationController;
|
||||
@Mock
|
||||
private ConversationNotificationManager mConversationNotificationManager;
|
||||
private FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
|
||||
|
||||
private NotificationPanelViewController mNotificationPanelViewController;
|
||||
@@ -223,7 +226,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
mDozeParameters, mCommandQueue, mVibratorHelper,
|
||||
mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
|
||||
mMetricsLogger, mActivityManager, mZenModeController, mConfigurationController,
|
||||
mFlingAnimationUtilsBuilder, mStatusBarTouchableRegionManager);
|
||||
mFlingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
|
||||
mConversationNotificationManager);
|
||||
mNotificationPanelViewController.initDependencies(mStatusBar, mGroupManager,
|
||||
mNotificationShelf, mNotificationAreaController, mScrimController);
|
||||
mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
|
||||
|
||||
Reference in New Issue
Block a user