I've been experimenting with the new Bubbles API recently. No matter what I do, the notifications that I expect to appear as a bubble always appear in the system tray as a normal notification.
I've written my own toy app, which I'll add here. I have also pulled down a couple of other apps from tutorials (here and here) that I have studied. In every single case, no bubble, just a system tray notification.
Since the sample apps assert that they can present bubbles, I assume that the problem must be somewhere in my emulator environment. I'm running an emulator that uses Android API R
. And I have enabled bubbles in the developer options:
Here is the relevant code from the app that I have developed:
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
}
}
And finally, the destination activity, which I don't think really matters too much since it only fires if the bubble were available to click: 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)
}
}
And that's really all there is to this. But when run this and click the button to display a bubble, I get this result:
@AndroidDev your code works fine in API level 29 and shows the notifications as bubbles but it does not work in Android R. I guess you should not worry about that as it is in preview stage and definitely not stable.
So if you run your code in an emulator with API level 29, it should work fine.
This issue is a regression from Android 10 and is reported here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With