目录
[📂 前言](#📂 前言)
[AR 眼镜系统版本](#AR 眼镜系统版本)
[1. 🔱 技术方案](#1. 🔱 技术方案)
[1.1 技术方案概述](#1.1 技术方案概述)
[1.2 实现方案](#1.2 实现方案)
[2. 💠 通知弹窗消失](#2. 💠 通知弹窗消失)
[2.1 通知弹窗显示时长到期后自动消失](#2.1 通知弹窗显示时长到期后自动消失)
[2.2 将通知添加到通知中心](#2.2 将通知添加到通知中心)
[3. ⚛️ 通知中心显示](#3. ⚛️ 通知中心显示)
[3.1 统一处理通知](#3.1 统一处理通知)
[2)处理 AR 眼镜通知添加](#2)处理 AR 眼镜通知添加)
[4)通知信息数据类 NotifyInfo](#4)通知信息数据类 NotifyInfo)
[3.2 分类显示 AR 眼镜以及手机端的通知](#3.2 分类显示 AR 眼镜以及手机端的通知)
[4. ✅ 小结](#4. ✅ 小结)
📂 前言
AR 眼镜系统版本
W517 Android9。
系统通知定制
系统通知的底层 实现主要依赖 Android 原生通知模块 NotificationManagerService ,系统通知的上层 UI 主要依赖于继承 NotificationListenerService 去实现,实现过程如下图所示,主要分为三步:1)应用 A 通过 sendNotification 发送通知;2)Android 通知模块 NotificationManagerService 接收到通知;3、应用 B 通过继承 NotificationListenerService监听到系统通知。对于底层实现感兴趣的同学可自行去深入了解,本文所讨论的系统通知实现方案主要针对于上层 UI。
那么,Android 原生系统通知是怎样实现的呢?答案很简单:通过 SystemUI 应用实现,SystemUI 通过继承 NotificationListenerService 监听系统通知,然后显示在通知栏。
但是,AR 眼镜系统与传统 Android 2D 存在较大显示与交互差异,且根据产品需求综合来看,本文采用类似 SystemUI 的方案,通知应用 通过继承 NotificationListenerService 实现系统通知的监听与显示。
1. 🔱 技术方案
1.1 技术方案概述
通知应用 通过继承 NotificationListenerService 实现系统通知的监听与显示,上层 UI 主要包括:通知弹窗、通知中心,系统通知定制的实现方案将分为两个篇章展开,分别是 通知弹窗篇 与 通知中心篇。
1.2 实现方案
接续上篇章 AR 眼镜之-系统通知定制(通知弹窗)-实现方案,showNotification 显示通知弹窗 View 后,需要处理通知弹窗消失的逻辑。
1)通知弹窗消失
-
通知弹窗显示时长到期后自动消失;
-
将通知添加到通知中心。
2)通知中心显示
-
统一处理通知;
-
分类显示 AR 眼镜以及手机端的通知。
2. 💠 通知弹窗消失
2.1 通知弹窗显示时长到期后自动消失
一般通知弹窗会规定显示时长,比如 3s 后自动消失。
/**
* 通知浮窗消失时间。单位:ms
*/
const val NOTIFICATION_DIALOG_TIME_OUT = 3000L
var timeOut: CountDownTimer? = null
timeOut = object : CountDownTimer(NOTIFICATION_DIALOG_TIME_OUT, 1000) {
override fun onTick(millisUntilFinished: Long) {}
override fun onFinish() {
addNotificationBar(context, notificationManagerBean)
timeOut?.cancel()
timeOut = null
}
}.start()
2.2 将通知添加到通知中心
// 弹窗消息通知消失后,添加到通知中心
addNotificationBar(context, notificationManagerBean)
/**
* 将通知添加到通知列表
*/
private fun addNotificationBar(
context: Context,
notificationManagerBean: NotificationManagerBean,
) {
if (notificationManagerBean.from == NotificationManagerBean.FROM_GLASS) {
notificationManagerBean.glassNotification?.let {
NotificationBarHelper.addNotification(context, it)
}
} else {
notificationManagerBean.phoneNotification?.let {
NotificationBarHelper.addNotification(context, it)
}
}
}
3. ⚛️ 通知中心显示
3.1 统一处理通知
1)统一处理通知中心的通知添加
object NotificationBarHelper {
private val TAG = "NotificationBarHelper"
private var instance: NotificationBar? = null
@JvmStatic
fun getInstance(context: Context): NotificationBar? {
if (instance == null) {
instance = NotificationBar(context, null)
}
return instance
}
@JvmStatic
fun release() {
instance = null
}
/**
* AR 眼镜通知添加
*/
@JvmStatic
fun addNotification(context: Context, sbn: StatusBarNotification){}
/**
* 手机端通知添加
*/
@JvmStatic
fun addNotification(context: Context, msg: MessageReqMsgNoti){}
}
2)处理 AR 眼镜通知添加
fun addNotification(context: Context, sbn: StatusBarNotification) {
val notifyInfo = NotifyInfo()
val packageName = sbn.packageName
val postTime = sbn.postTime
sbn.notification.apply {
val smallIcon = smallIcon?.loadDrawable(context)
// val largeIcon = getLargeIcon()?.loadDrawable(context)
val title = extras.getString(Notification.EXTRA_TITLE, "")
val content = sbn.notification.extras.getCharSequence(Notification.EXTRA_TEXT, "")
val progress = extras.getInt(Notification.EXTRA_PROGRESS)
// val progressMax = extras.getInt(Notification.EXTRA_PROGRESS_MAX)
// val progressInd = extras.getBoolean(Notification.EXTRA_PROGRESS_INDETERMINATE)
// val priority = priority
val contentIntent = contentIntent
// val deleteIntent = deleteIntent
// val whenTime = `when`
// val showWhen = extras.getBoolean(Notification.EXTRA_SHOW_WHEN)
// val channelID = extras.getString(Notification.EXTRA_CHANNEL_ID, "")
// val contentView = contentView
// val bigContentView = bigContentView
// val headsUpContentView = headsUpContentView
// Log.e(
// TAG,
// "addNotification: notification\n" + "packageName = $packageName\n" + "postTime = $postTime\n" + "smallIcon = $smallIcon\n" + "largeIcon = $largeIcon\n" + "title = $title\n" + "content = $content\n" + "progress = $progress\n" + "progressMax = $progressMax\n" + "progressInd = $progressInd\n" + "priority = $priority\n" + "contentIntent = $contentIntent\n" + "deleteIntent = $deleteIntent\n" + "whenTime = $whenTime\n" + "showWhen = $showWhen\n" + "channelID = $channelID\n" + "contentView = $contentView\n" + "bigContentView = $bigContentView\n" + "headsUpContentView = $headsUpContentView\n"
// )
// actions?.forEach { action ->
val actionIcon = action.getIcon()?.loadDrawable(context)
// val actionIcon = null
// val actionTitle = action.title
// val actionIntent = action.actionIntent
// Log.e(
// TAG,
// "addNotification: action\n" + "actionIcon = $actionIcon\n" + "actionTitle = $actionTitle\n" + "actionIntent = $actionIntent\n"
// )
// }
notifyInfo.title = title
notifyInfo.packageName = packageName
notifyInfo.icon = smallIcon
notifyInfo.msg = content.toString()
notifyInfo.time = postTime
notifyInfo.contentIntent = contentIntent
val style = extras.getString(Notification.EXTRA_TEMPLATE, "")
if (style.isNotEmpty()) {
when (style) {
Notification.BigTextStyle::class.java.name -> {
val bigContentTitle =
sbn.notification.extras.getCharSequence(Notification.EXTRA_TITLE_BIG)
val summaryText =
sbn.notification.extras.getCharSequence(Notification.EXTRA_SUMMARY_TEXT)
val bigText =
sbn.notification.extras.getCharSequence(Notification.EXTRA_BIG_TEXT)
// Log.e(
// TAG,
// "addNotification: BigTextStyle\nbigContentTitle = $bigContentTitle\nsummaryText = $summaryText\nbigText = $bigText\n"
// )
if (bigContentTitle?.isNotEmpty() == true) notifyInfo.title =
bigContentTitle.toString()
if (bigText?.isNotEmpty() == true) notifyInfo.msg = bigText.toString()
}
Notification.BigPictureStyle::class.java.name -> {
val bigContentTitle =
sbn.notification.extras.getCharSequence(Notification.EXTRA_TITLE_BIG)
val summaryText =
sbn.notification.extras.getCharSequence(Notification.EXTRA_SUMMARY_TEXT)
val bigPicture =
sbn.notification.extras.getParcelable<Bitmap>(Notification.EXTRA_PICTURE)
// Log.e(
// TAG,
// "addNotification: BigPictureStyle\nbigContentTitle = $bigContentTitle\nsummaryText = $summaryText\nbigPicture = $bigPicture\n"
// )
if (bigContentTitle?.isNotEmpty() == true) notifyInfo.title =
bigContentTitle.toString()
if (bigPicture != null) notifyInfo.picture = bigPicture
}
Notification.InboxStyle::class.java.name -> {
val bigContentTitle =
sbn.notification.extras.getCharSequence(Notification.EXTRA_TITLE_BIG)
val summaryText =
sbn.notification.extras.getCharSequence(Notification.EXTRA_SUMMARY_TEXT)
val textLinesArray =
sbn.notification.extras.getCharSequenceArray(Notification.EXTRA_TEXT_LINES)
var textLines = ""
if (!textLinesArray.isNullOrEmpty()) {
val sb: StringBuilder = StringBuilder()
for (msg in textLinesArray) if (msg.isNotEmpty()) {
sb.append(msg.toString())
sb.append('\n')
}
textLines = sb.toString().trim { it <= ' ' }
}
// Log.e(
// TAG,
// "addNotification: BigPictureStyle\nbigContentTitle = $bigContentTitle\nsummaryText = $summaryText\ntextLines = $textLines\n"
// )
if (bigContentTitle?.isNotEmpty() == true) notifyInfo.title =
bigContentTitle.toString()
if (textLines.isNotEmpty()) notifyInfo.msg = textLines
}
Notification.MediaStyle::class.java.name -> {
}
Notification.DecoratedCustomViewStyle::class.java.name -> {
}
Notification.DecoratedMediaCustomViewStyle::class.java.name -> {
}
Notification.MessagingStyle::class.java.name -> {
}
// Notification.CallStyle::class.java.name -> {
//
// }
else -> {}
}
}
// if (title.isNotEmpty()) {
if (progress > 0) {
notifyInfo.style = NOTIFICATION_STYLE_PROGRESS
Log.i(TAG, "addNotification: update progress.progress = $progress,style = $style\n")
instance?.updateGlassNotifyInfo(notifyInfo) ?: Log.e(
TAG, "addNotification: NotificationBar has not init..."
)
} else {
Log.i(TAG, "addNotification: add notify.style = $style\n")
instance?.addGlassNotifyInfo(notifyInfo) ?: Log.e(
TAG, "addNotification: NotificationBar has not init..."
)
}
// } else {
// Log.e(TAG, "addNotification: title is empty!!!")
// }
}
}
3)处理手机端通知添加
fun addNotification(context: Context, msg: MessageReqMsgNoti) {
val notifyInfo = NotifyInfo(
msg.title,
AppUtils.getPhoneAppName(context, msg),
AppUtils.getPhoneAppIcon(context, msg),
msg.text,
msg.timeStamp
)
if (msg.title.isNotEmpty()) {
instance?.addPhoneNotifyInfo(notifyInfo) ?: Log.e(
TAG, "addNotification: phone ------ NotificationBar has not init..."
)
} else {
Log.e(TAG, "addNotification: phone ------ title is empty!!!")
}
}
4)通知信息数据类 NotifyInfo
data class NotifyInfo(
var title: String = "",
var packageName: String = "",
var icon: Drawable? = null,
var msg: String = "",
var time: Long = System.currentTimeMillis(),
var style: String = "", // ProgressStyle
var type: Int = 0,
var location: String = "",
var picture: Bitmap? = null,
var foldInfoList: MutableList<NotifyInfo> = mutableListOf(),
var contentIntent: PendingIntent? = null,
)
3.2 分类显示 AR 眼镜以及手机端的通知
此部分主要在 UI 布局设计这块,如下图所示:
通知中心,由于没有特殊复杂的产品设计,本文不再赘述,主要注意如下几点即可:
-
使用两个 Table 页去区分 AR 眼镜与手机端的通知;
-
然后使用 RecyclerView 列表去展示对应通知;
-
同时处理点击 Table 页时对应通知的数据切换;
-
处理清除按钮对通知的清除;
具体通知中心的代码,参考附录1。
4. ✅ 小结
对于系统通知定制(通知中心),本文只是一个基础实现方案,更多业务细节请参考产品逻辑去实现。
另外,由于本人能力有限,如有错误,敬请批评指正,谢谢。
附录1:通知中心代码
class NotificationBar(context: Context, attrs: AttributeSet?) : ConstraintLayout(context, attrs),
BarMonitor {
val glassNotifyInfoList: MutableList<NotifyInfo> = mutableListOf()
val phoneNotifyInfoList: MutableList<NotifyInfo> = mutableListOf()
private lateinit var mRootView: View
private lateinit var notifyClear: View
private lateinit var notifyRecyclerView: AGGRecyclerView
private lateinit var notifyNoMsgLayout: LinearLayout
private lateinit var notifyNoMsgText: AGGTextView
private lateinit var glassTitle: AGGTextView
private lateinit var phoneTitle: AGGTextView
private lateinit var foldPage: NotificationFoldPage
private val TAG = NotificationBar::class.java.simpleName
private val NOTIFY_COUNT_NUM = 100
private val NOTIFY_FOLD_COUNT_NUM = 3
private val notifyAdapter by lazy { NotifyAdapter() }
private var isClickNotifyGlassBtn = false
private var curOpenedFoldViewNotifyInfo: NotifyInfo? = null
init {
initView()
initNotifyTitle()
initLiveDataBus()
initViewStatus()
}
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
if (event.keyCode == KeyEvent.KEYCODE_BACK) {
Log.i(TAG, "dispatchKeyEvent: KEYCODE_BACK")
LiveDataBus.get().with(Constants.NOTIFICATION_EVENT_BUS_CLOSE_FOLD_PAGE).value = true
}
return super.dispatchKeyEvent(event)
}
override fun isBarVisible(): Boolean = mRootView.visibility == VISIBLE
fun updateBarVisible(visible: Boolean) {
if (visible) {
if (mRootView.visibility != VISIBLE) mRootView.visibility = VISIBLE
} else {
if (mRootView.visibility == VISIBLE) mRootView.visibility = INVISIBLE
}
callBarStateChanged()
}
fun addGlassNotifyInfo(notifyInfo: NotifyInfo) {
judgeFoldNotifyInfo(notifyInfo, glassNotifyInfoList)
if (isClickNotifyGlassBtn) {
notifyAdapter.addInfoList(glassNotifyInfoList)
notifyDataSetChanged()
}
notifyClear.visibility = VISIBLE
}
fun addPhoneNotifyInfo(notifyInfo: NotifyInfo) {
judgeFoldNotifyInfo(notifyInfo, phoneNotifyInfoList)
if (!isClickNotifyGlassBtn) {
notifyAdapter.addInfoList(phoneNotifyInfoList)
notifyDataSetChanged()
}
notifyClear.visibility = VISIBLE
}
fun updateGlassNotifyInfo(notifyInfo: NotifyInfo) {
var isUpdate = false
for (i in 0 until glassNotifyInfoList.size) {
if (glassNotifyInfoList[i].title == notifyInfo.title) {
glassNotifyInfoList[i] = notifyInfo
isUpdate = true
break
}
}
if (isClickNotifyGlassBtn && isUpdate) {
notifyAdapter.updateInfo(notifyInfo)
notifyDataSetChanged()
}
if (!isUpdate) addGlassNotifyInfo(notifyInfo)
}
@SuppressLint("NotifyDataSetChanged")
fun notifyDataSetChanged() {
if (glassNotifyInfoList.isEmpty() && phoneNotifyInfoList.isEmpty()) {
notifyRecyclerView.visibility = INVISIBLE
notifyNoMsgLayout.visibility = VISIBLE
notifyClear.visibility = INVISIBLE
} else {
notifyAdapter.notifyDataSetChanged()
notifyRecyclerView.scrollToPosition(0)
notifyRecyclerView.visibility = VISIBLE
notifyNoMsgLayout.visibility = INVISIBLE
notifyClear.visibility = VISIBLE
}
}
fun initViewStatus() {
phoneTitle.setBackgroundResource(R.drawable.notification_bar_title_item_bg_select)
glassTitle.setBackgroundColor(Color.TRANSPARENT)
notifyAdapter.addInfoList(phoneNotifyInfoList)
if (phoneNotifyInfoList.isEmpty()) {
notifyRecyclerView.visibility = INVISIBLE
notifyNoMsgLayout.visibility = VISIBLE
updateNoMsgText()
if (glassNotifyInfoList.isEmpty()) notifyClear.visibility = INVISIBLE
else notifyClear.visibility = VISIBLE
} else {
notifyDataSetChanged()
notifyRecyclerView.visibility = VISIBLE
notifyNoMsgLayout.visibility = INVISIBLE
}
}
private fun initView() {
mRootView = LayoutInflater.from(context)
.inflate(R.layout.notification_layout_notificationbar, this, true)
notifyClear = mRootView.findViewById(R.id.notify_clear)
notifyRecyclerView = mRootView.findViewById(R.id.notify_list)
notifyNoMsgLayout = mRootView.findViewById(R.id.notify_no_msg_layout)
notifyNoMsgText = mRootView.findViewById(R.id.notify_no_msg_text)
glassTitle = mRootView.findViewById(R.id.glassTitle)
phoneTitle = mRootView.findViewById(R.id.phoneTitle)
notifyRecyclerView.apply {
layoutManager = LinearLayoutManager(context)
addItemDecoration(SpacesItemDecoration((10 * context.resources.displayMetrics.density + 0.5f).toInt()))
adapter = notifyAdapter
isFocusableInTouchMode = true
}
foldPage = mRootView.findViewById(R.id.fold_page)
mRootView.postDelayed({
registerPackageRemoved(context)
register(context)
}, 3000)
// 重启/开机后,AR眼镜自动连接上手机时,通知中心不一定收到ACTION_LINK_STATE_CHANGED状态的回调,于是在重启/开机一定时间后主动获取状态。
mRootView.postDelayed({ updateNoMsgText() }, 15000)
}
@SuppressLint("NotifyDataSetChanged")
private fun initNotifyTitle() {
notifyClear.setOnClickListener {
SoundPoolTools.playNotifyClear(context.applicationContext)
if (notifyAdapter.itemCount == 0) {
handleClearNotification()
} else {
notifyRecyclerView.clearAllItem(object : AnimatorListener {
override fun onAnimationStart(p0: Animator) {}
override fun onAnimationEnd(p0: Animator) {
handleClearNotification()
}
override fun onAnimationCancel(p0: Animator) {}
override fun onAnimationRepeat(p0: Animator) {}
})
}
}
glassTitle.setOnHoverListener { v, event ->
if (event.action == MotionEvent.ACTION_HOVER_ENTER) {
glassTitle.setBackgroundResource(R.drawable.notification_bar_title_item_bg_foc)
} else if (event.action == MotionEvent.ACTION_HOVER_EXIT) {
if (isClickNotifyGlassBtn) {
glassTitle.setBackgroundResource(R.drawable.notification_bar_title_item_bg_select)
} else {
glassTitle.setBackgroundColor(Color.TRANSPARENT)
}
}
false
}
glassTitle.setOnClickListener {
if (!isClickNotifyGlassBtn) {
isClickNotifyGlassBtn = true
glassTitle.setBackgroundResource(R.drawable.notification_bar_title_item_bg_select)
phoneTitle.setBackgroundColor(Color.TRANSPARENT)
notifyAdapter.addInfoList(glassNotifyInfoList)
if (glassNotifyInfoList.isEmpty()) {
notifyRecyclerView.visibility = INVISIBLE
notifyNoMsgLayout.visibility = VISIBLE
updateNoMsgText()
if (phoneNotifyInfoList.isEmpty()) notifyClear.visibility = INVISIBLE
else notifyClear.visibility = VISIBLE
} else {
notifyDataSetChanged()
notifyRecyclerView.visibility = VISIBLE
notifyNoMsgLayout.visibility = INVISIBLE
}
}
}
phoneTitle.setOnHoverListener { v, event ->
if (event.action == MotionEvent.ACTION_HOVER_ENTER) {
phoneTitle.setBackgroundResource(R.drawable.notification_bar_title_item_bg_foc)
} else if (event.action == MotionEvent.ACTION_HOVER_EXIT) {
if (isClickNotifyGlassBtn) {
phoneTitle.setBackgroundColor(Color.TRANSPARENT)
} else {
phoneTitle.setBackgroundResource(R.drawable.notification_bar_title_item_bg_select)
}
}
false
}
phoneTitle.setOnClickListener {
if (isClickNotifyGlassBtn) {
isClickNotifyGlassBtn = false
initViewStatus()
}
}
}
private fun initLiveDataBus() {
LiveDataBus.get().with(
Constants.NOTIFICATION_EVENT_BUS_OPEN_FOLD_PAGE, NotifyInfo::class.java
).observeForever {
curOpenedFoldViewNotifyInfo = it
foldPage.visibility = VISIBLE
foldPage.addFoldNotifyInfo(it.foldInfoList)
}
LiveDataBus.get()
.with(Constants.NOTIFICATION_EVENT_BUS_CLOSE_FOLD_PAGE, Boolean::class.java)
.observeForever {
curOpenedFoldViewNotifyInfo = null
foldPage.visibility = GONE
}
LiveDataBus.get().with(Constants.NOTIFICATION_EVENT_BUS_CLEAR_FOLD_VIEW, String::class.java)
.observeForever {
curOpenedFoldViewNotifyInfo = null
foldPage.visibility = GONE
clearCurFoldItem(
if (isClickNotifyGlassBtn) glassNotifyInfoList else phoneNotifyInfoList, it
)
}
LiveEventBus.get(NOTIFICATION_PHONE_LINK_STATE_CHANGED, Boolean::class.java)
.observeForever { updateNoMsgText() }
}
private fun registerPackageRemoved(context: Context) {
val filter = IntentFilter()
filter.addAction(Intent.ACTION_PACKAGE_REMOVED)
filter.addDataScheme("package")
context.registerReceiver(object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val pkgName = intent.data?.schemeSpecificPart
Log.d("NotificationBar", "onReceive: $pkgName removed")
val tempRemoveList: MutableList<NotifyInfo> = mutableListOf()
for (i in 0 until glassNotifyInfoList.size) {
if (glassNotifyInfoList[i].packageName == pkgName) {
tempRemoveList.add(glassNotifyInfoList[i])
}
}
if (tempRemoveList.isNotEmpty()) {
glassNotifyInfoList.removeAll(tempRemoveList)
if (isClickNotifyGlassBtn) {
if (glassNotifyInfoList.isEmpty() && phoneNotifyInfoList.isEmpty()) {
notifyClear.visibility = INVISIBLE
} else {
notifyClear.visibility = VISIBLE
}
notifyAdapter.addInfoList(glassNotifyInfoList)
notifyDataSetChanged()
updateNoMsgText()
}
curOpenedFoldViewNotifyInfo?.let {
if (pkgName == it.packageName) {
LiveDataBus.get().with(Constants.NOTIFICATION_EVENT_BUS_CLEAR_FOLD_VIEW)
.setValue(pkgName)
}
}
}
}
}, filter, null, Handler())
}
private fun register(context: Context) {
val filter = IntentFilter()
filter.addAction(Intent.ACTION_TIME_TICK)
filter.addAction(Intent.ACTION_TIME_CHANGED)
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED)
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED)
context.registerReceiver(object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
notifyAllTime()
}
}, filter, null, Handler())
}
private fun updateNoMsgText() {
if (notifyNoMsgLayout.isVisible) {
if (isClickNotifyGlassBtn) {
notifyNoMsgText.text = context.getString(R.string.notification_glass_no_msg)
} else {
if (PhoneNotificationHelper.isConnectPhone()) {
notifyNoMsgText.text = context.getString(R.string.notification_glass_no_msg)
} else {
notifyNoMsgText.text = context.getString(R.string.notification_phone_no_msg)
}
}
}
}
private fun notifyAllTime() {
if (glassNotifyInfoList.isNotEmpty() || phoneNotifyInfoList.isNotEmpty()) {
notifyAdapter.notifyItemRangeChanged(0, notifyAdapter.itemCount, "update_time")
}
}
/**
* 同一应用3条及以上通知,折叠显示判断
*/
private fun judgeFoldNotifyInfo(info: NotifyInfo, infoList: MutableList<NotifyInfo>) {
val foldInfoList: MutableList<NotifyInfo> = mutableListOf()
for (i in 0 until infoList.size) {
if (infoList[i].packageName == info.packageName) {
if (infoList[i].foldInfoList.size >= NOTIFY_FOLD_COUNT_NUM) { // 已经折叠
if (infoList[i].foldInfoList.size == NOTIFY_COUNT_NUM) infoList[i].foldInfoList.remove(
infoList[i].foldInfoList[NOTIFY_COUNT_NUM - 1]
)
infoList[i].foldInfoList.add(0, info)
// 移到最前方
val notifyInfoTemp = infoList[i]
infoList.remove(notifyInfoTemp)
infoList.add(0, notifyInfoTemp)
// 更新折叠页面
curOpenedFoldViewNotifyInfo?.let {
if (it.packageName == info.packageName) {
foldPage.updateFoldNotifyInfo(notifyInfoTemp.foldInfoList)
curOpenedFoldViewNotifyInfo = notifyInfoTemp
}
}
return
} else {
foldInfoList.add(infoList[i])
}
}
}
foldInfoList.add(0, info)
// 判断是否折叠通知
if (foldInfoList.size >= NOTIFY_FOLD_COUNT_NUM) {
info.type = Constants.NOTIFICATION_TYPE_FOLD
info.foldInfoList = foldInfoList
infoList.removeAll(foldInfoList)
infoList.add(0, info)
} else {
if (infoList.size == NOTIFY_COUNT_NUM) infoList.remove(infoList[NOTIFY_COUNT_NUM - 1])
infoList.add(0, info)
}
}
/**
* 清除当前的折叠通知Item项
*/
@SuppressLint("NotifyDataSetChanged")
private fun clearCurFoldItem(notifyInfoList: MutableList<NotifyInfo>, pkgName: String) {
val tempNotifyInfoList: MutableList<NotifyInfo> = mutableListOf()
for (i in 0 until notifyInfoList.size) {
if (notifyInfoList[i].packageName == pkgName) {
tempNotifyInfoList.add(notifyInfoList[i])
}
}
notifyInfoList.removeAll(tempNotifyInfoList)
notifyAdapter.addInfoList(notifyInfoList)
if (notifyInfoList.isEmpty()) {
notifyAdapter.notifyDataSetChanged()
notifyRecyclerView.visibility = INVISIBLE
notifyNoMsgLayout.visibility = VISIBLE
updateNoMsgText()
if (glassNotifyInfoList.isEmpty() && phoneNotifyInfoList.isEmpty()) {
notifyClear.visibility = INVISIBLE
} else {
notifyClear.visibility = VISIBLE
}
} else {
notifyDataSetChanged()
}
}
private fun handleClearNotification() {
glassNotifyInfoList.clear()
phoneNotifyInfoList.clear()
notifyAdapter.clear()
notifyRecyclerView.visibility = INVISIBLE
notifyNoMsgLayout.visibility = VISIBLE
updateNoMsgText()
notifyClear.visibility = INVISIBLE
}
}