Android Q 目前已经发布到最后一个 Beta 版本了,再过不久 Q 正式版本就要推出了。Q 版本中新增了一些有趣的东西,必须 Bubbles,对话框中添加设置项等。本文主要简述 Bubble 新特性。

简述

Bubble 意为气泡,是 Android 用来取代 SYSTEM_ALERT_WINDOW 的一个组件。目前 Q 只有开发者模式下才可以使用气泡。官网上是这么说的:

在 Android Q 开发者预览版中,气泡目前面向所有用户启用。在最终版本中,只有开发者可以使用气泡。

Bubble 和 Alert Window 不同的地方在于 Bubble 是内置于 Notification 中的,只需要在现有 通知的基础上进行稍微的改动即可显示气泡。

SYSTEM_ALERT_WINDOW 的优先级是很高的,可以叠加在其它应用的上层,因此 Bubble 也有此特性。它不仅可以浮动在其它应用上层,而且可以进行移动或者进行展开、折叠或者关闭。

Android Q 预览版上要使用Bubble 功能需要在开发者选项中打开气泡选项。否则即使满足气泡显示条件也会以传统通知的方式进行显示。

创建 Bubble

配置Activity

Bubble 点击可以显示一个 Activity,此 Activity 必须满足潜入、调整大小等特性,即需要在 Manifest 文件中要对显示的 Activity 进行如下配置,如果应用可以显示多个相同类型的气泡,则需要在 Manifest 文件中配置 documentLaunchMode 属性为always:

<activity
android:name=".BubbleLoginActivity"
android:label="@string/title_activity_bubble_login"
android:allowEmbedded="true"
android:resizeableActivity="true"
android:documentLaunchMode="always" >
</activity>

documentLaunchMode 属性的修改会改变对应 Activity 的启动方式,也会改变启动动画。

具体方式为:

  • intoExisting: activity 会为该document请求一个已经存在的task,这与 设置FLAG_ACTIVITY_NEW_DOCUMENT 且不设置 FLAG_ACTIVITY_MULTIPLE_TASK 有相同的效果

  • always: ctivity 会为该document创建一个新的task,即使该document已经被打开了,这与设置 FLAG_ACTIVITY_NEW_DOCUMENT 且设置 FLAG_ACTIVITY_MULTIPLE_TASK 有相同的效果

  • none: activity 不会为 document 创建新的task,该app被设置为 single task 的模式,它会重新调用用户唤醒的所有activity中的最近的一个

  • never: activity 不会为document创建一个新的task,设置这个值复写了 FLAG_ACTIVITY_NEW_DOCUMENT 和 FLAG_ACTIVITY_MULTIPLE_TASK 标签。如果其中一个标签被设置,并且overview screen 显示该app为
    single task 模式。 则该activity 会重新调用用户最近唤醒的activity

none 或 nerver 使用时,activity必须设置为 launchMode=”standard” ,如果该属性没有设置,documentLaunchMode=”none” 属性就会被使用

创建通知

前面已经说过 Bubble 是内置于通知系统中的,所以接下来就是按照传统的步骤创建通知。但是需要创建Notification.BubbleMetadata,并将其添加到通知中:

// 创建通知渠道
val notificationManager: NotificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH))

// 创建点击 Bubble 的intent
val target = Intent(applicationContext, BubbleLoginActivity::class.java)
val bubbleIntent: PendingIntent = PendingIntent.getActivity(applicationContext, 0, target, 0)

// 创建 BubbleMetadata
val bubbleMetadata = Notification.BubbleMetadata.Builder()
.setIntent(bubbleIntent)
.setDesiredHeight(600)
.setIcon(Icon.createWithResource(applicationContext, R.drawable.ic_notifications))
.build()

// 创建 Notification 并发送
val notification = Notification.Builder(applicationContext, CHANNEL_ID)
.setContentIntent(bubbleIntent)
.setContentTitle(resources.getString(R.string.notification))
.setContentText(resources.getString(R.string.notification_contnet_text))
.setBubbleMetadata(bubbleMetadata)
.setSmallIcon(R.drawable.ic_notifications)
.build()

notificationManager.notify(CHANNEL_TAG, 0, notification)

当您第一次发送通知以显示气泡时,此通知必须在具有 IMPORTANCE_HIGH的通知渠道中。这是因为气泡由通知重要程度管理器处理。如果系统在用户有机会允许或屏蔽气泡之前降低了通知的重要程度,则通知将无法显示为气泡。

如需在创建 Bubble 时自动展开对应的 activity,只需要在 BubbleMetadata 中设置:setAutoExpandBubble()setSuppressInitialNotification()为true。

val bubbleMetadata = Notification.BubbleMetadata.Builder()
.setIntent(bubbleIntent)
.setDesiredHeight(600)
.setIcon(Icon.createWithResource(applicationContext, R.drawable.ic_notifications))
.setAutoExpandBubble(true)
.setSuppressNotification(true)
.build()

后台通知气泡

按照官网上的说法,如果应用在后台,那么显示气泡的条件有以下两个:

  • 通知使用了 MessageStye,并且添加Person
  • 通知来自对 Service.startForeground 的调用,类别为 CATEGORY_CALL,并添加了 Person

这两个条件并非最终的版本,后续可能要发生变化。

但是测试了第一个条件,还是以传统通知的方式弹出的。目前还不知道具体问题出在哪😖😖😖

Bubble 的生命周期

Bubble 展开的 Activity 遵循传统 Activity 的生命周期,而且是一个单独的 Activity 栈,当气泡折叠或者关闭时此activity 会销毁。

Demo

bubble

代码地址:Bubble Demo