为什么气泡显示为正常通知?
Why are Bubbles appearing as normal Notifications?
我最近一直在试用新的 Bubbles API。无论我做什么,我希望显示为气泡的通知总是作为正常通知出现在系统托盘中。
我已经编写了自己的玩具应用程序,我将在此处添加。我还从我研究过的教程 (here and here) 中下载了其他几个应用程序。在每种情况下,都没有气泡,只有系统托盘通知。
由于示例应用断言它们会出现气泡,我认为问题一定出在我的模拟器环境中。我正在 运行 使用 Android API R
的模拟器。我在开发者选项中启用了气泡:
这是我开发的应用程序的相关代码:
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.bubbles">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".BubbleActivity"
android:allowEmbedded="true"
android:documentLaunchMode="always"
android:resizeableActivity="true" />
<activity
android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity.kt
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
class MainActivity : AppCompatActivity() {
private lateinit var bubbleViewModel: BubbleViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
bubbleViewModel = ViewModelProvider(
this, BubbleViewModelFactory(this.application))
.get(BubbleViewModel::class.java)
}
fun blowBubble(view: View) {
bubbleViewModel.showBubble()
}
}
BubbleViewModel.kt
class BubbleViewModel(application: Application): AndroidViewModel(application) {
private val notificationHelper = NotificationHelper(getApplication())
init {
notificationHelper.createNotificationChannels()
}
fun showBubble() {
viewModelScope.launch{
withContext(Dispatchers.Main) {
with (notificationHelper) {
if (canBubble())
showNotification()
}
}
}
}
}
NotificationHelper.kt
class NotificationHelper(private val context: Context) {
private val notificationManager = context.getSystemService(NotificationManager::class.java)
private lateinit var channel: NotificationChannel
fun createNotificationChannels() {
channel = NotificationChannel(
CHANNEL_NEW_MESSAGES,
context.getString(R.string.channel_name),
NotificationManager.IMPORTANCE_HIGH)
with(channel) {
enableVibration(true)
lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
description = context.getString(R.string.channel_description)
setAllowBubbles(true)
}
Log.d("bubble", "Can Bubble: $channel.canBubble()")
notificationManager?.let {
it.createNotificationChannel(channel)
}
}
@WorkerThread
fun showNotification() {
val bubbleIntent = PendingIntent.getActivity(
context,
REQUEST_BUBBLE,
Intent(context, BubbleActivity::class.java).setAction(Intent.ACTION_VIEW),
PendingIntent.FLAG_UPDATE_CURRENT)
val bubbleMetaData = Notification.BubbleMetadata.Builder()
.setDesiredHeight(600)
.createIntentBubble(bubbleIntent, Icon.createWithResource(context, R.drawable.baseball))
.setAutoExpandBubble(false)
.setSuppressNotification(false)
.build()
val person = Person.Builder()
.setIcon(Icon.createWithResource(context, R.drawable.baseball))
.setName("Bubbles...")
.setImportant(true)
.build()
val style = Notification.MessagingStyle(person)
.addMessage("...are the Best!", System.currentTimeMillis(), person)
val builder = Notification.Builder(context, CHANNEL_NEW_MESSAGES)
.setBubbleMetadata(bubbleMetaData)
.setContentIntent(bubbleIntent)
// .setContentTitle("Title")
// .setContentText("Hello this is a notification")
.setSmallIcon(R.drawable.baseball)
.setShowWhen(true)
.setAutoCancel(true)
.setStyle(style)
// .addPerson(person.uri)
notificationManager?.notify(0, builder.build())
}
fun canBubble(): Boolean {
notificationManager?.let {
val channel = it.getNotificationChannel(CHANNEL_NEW_MESSAGES)
return it.areBubblesAllowed() && channel.canBubble()
}
return false
}
companion object {
private const val CHANNEL_NEW_MESSAGES = "new_messages"
const val REQUEST_BUBBLE = 2
}
}
最后,目的地 activity,我认为这并不重要,因为它只会在气泡可供点击时触发:
BubbleActivity.kt
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class BubbleActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_bubble)
}
}
这就是全部内容。但是当运行这个并点击按钮显示一个气泡时,我得到这个结果:
@Android开发您的代码在 API 级别 29 中运行良好,并将通知显示为气泡,但在 Android R 中不起作用。我想您不必担心因为它处于预览阶段并且绝对不稳定。
因此,如果您 运行 您的代码在 API 级别 29 的模拟器中,它应该可以正常工作。
此问题是 Android 10 的回归,已报告 here
我一直在为同样的问题而苦苦挣扎,但是当我 运行 Google 的示例应用程序 People 时它工作得很好。
来自https://developer.android.com/guide/topics/ui/bubbles:
If an app targets Android 11 or higher, a notification doesn't appear
as a bubble unless it meets the conversation requirements.
这些要求中提到了您似乎缺少的这一部分:
Only notifications with an associated shortcut are able to bubble.
如何设置快捷方式(以及其他所有内容)可以在他们提到的示例中看到:https://github.com/android/user-interface-samples/blob/main/People/app/src/main/java/com/example/android/people/data/NotificationHelper.kt
我最近一直在试用新的 Bubbles API。无论我做什么,我希望显示为气泡的通知总是作为正常通知出现在系统托盘中。
我已经编写了自己的玩具应用程序,我将在此处添加。我还从我研究过的教程 (here and here) 中下载了其他几个应用程序。在每种情况下,都没有气泡,只有系统托盘通知。
由于示例应用断言它们会出现气泡,我认为问题一定出在我的模拟器环境中。我正在 运行 使用 Android API R
的模拟器。我在开发者选项中启用了气泡:
这是我开发的应用程序的相关代码:
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.bubbles">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".BubbleActivity"
android:allowEmbedded="true"
android:documentLaunchMode="always"
android:resizeableActivity="true" />
<activity
android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity.kt
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
class MainActivity : AppCompatActivity() {
private lateinit var bubbleViewModel: BubbleViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
bubbleViewModel = ViewModelProvider(
this, BubbleViewModelFactory(this.application))
.get(BubbleViewModel::class.java)
}
fun blowBubble(view: View) {
bubbleViewModel.showBubble()
}
}
BubbleViewModel.kt
class BubbleViewModel(application: Application): AndroidViewModel(application) {
private val notificationHelper = NotificationHelper(getApplication())
init {
notificationHelper.createNotificationChannels()
}
fun showBubble() {
viewModelScope.launch{
withContext(Dispatchers.Main) {
with (notificationHelper) {
if (canBubble())
showNotification()
}
}
}
}
}
NotificationHelper.kt
class NotificationHelper(private val context: Context) {
private val notificationManager = context.getSystemService(NotificationManager::class.java)
private lateinit var channel: NotificationChannel
fun createNotificationChannels() {
channel = NotificationChannel(
CHANNEL_NEW_MESSAGES,
context.getString(R.string.channel_name),
NotificationManager.IMPORTANCE_HIGH)
with(channel) {
enableVibration(true)
lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
description = context.getString(R.string.channel_description)
setAllowBubbles(true)
}
Log.d("bubble", "Can Bubble: $channel.canBubble()")
notificationManager?.let {
it.createNotificationChannel(channel)
}
}
@WorkerThread
fun showNotification() {
val bubbleIntent = PendingIntent.getActivity(
context,
REQUEST_BUBBLE,
Intent(context, BubbleActivity::class.java).setAction(Intent.ACTION_VIEW),
PendingIntent.FLAG_UPDATE_CURRENT)
val bubbleMetaData = Notification.BubbleMetadata.Builder()
.setDesiredHeight(600)
.createIntentBubble(bubbleIntent, Icon.createWithResource(context, R.drawable.baseball))
.setAutoExpandBubble(false)
.setSuppressNotification(false)
.build()
val person = Person.Builder()
.setIcon(Icon.createWithResource(context, R.drawable.baseball))
.setName("Bubbles...")
.setImportant(true)
.build()
val style = Notification.MessagingStyle(person)
.addMessage("...are the Best!", System.currentTimeMillis(), person)
val builder = Notification.Builder(context, CHANNEL_NEW_MESSAGES)
.setBubbleMetadata(bubbleMetaData)
.setContentIntent(bubbleIntent)
// .setContentTitle("Title")
// .setContentText("Hello this is a notification")
.setSmallIcon(R.drawable.baseball)
.setShowWhen(true)
.setAutoCancel(true)
.setStyle(style)
// .addPerson(person.uri)
notificationManager?.notify(0, builder.build())
}
fun canBubble(): Boolean {
notificationManager?.let {
val channel = it.getNotificationChannel(CHANNEL_NEW_MESSAGES)
return it.areBubblesAllowed() && channel.canBubble()
}
return false
}
companion object {
private const val CHANNEL_NEW_MESSAGES = "new_messages"
const val REQUEST_BUBBLE = 2
}
}
最后,目的地 activity,我认为这并不重要,因为它只会在气泡可供点击时触发: BubbleActivity.kt
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class BubbleActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_bubble)
}
}
这就是全部内容。但是当运行这个并点击按钮显示一个气泡时,我得到这个结果:
@Android开发您的代码在 API 级别 29 中运行良好,并将通知显示为气泡,但在 Android R 中不起作用。我想您不必担心因为它处于预览阶段并且绝对不稳定。
因此,如果您 运行 您的代码在 API 级别 29 的模拟器中,它应该可以正常工作。
此问题是 Android 10 的回归,已报告 here
我一直在为同样的问题而苦苦挣扎,但是当我 运行 Google 的示例应用程序 People 时它工作得很好。
来自https://developer.android.com/guide/topics/ui/bubbles:
If an app targets Android 11 or higher, a notification doesn't appear as a bubble unless it meets the conversation requirements.
这些要求中提到了您似乎缺少的这一部分:
Only notifications with an associated shortcut are able to bubble.
如何设置快捷方式(以及其他所有内容)可以在他们提到的示例中看到:https://github.com/android/user-interface-samples/blob/main/People/app/src/main/java/com/example/android/people/data/NotificationHelper.kt