通知的介绍及使用

0. 重要提醒

📌 XCD(Android U)新增发送通知权限,未申请权限将无法发送通知,详情见 2.1 节。 📌 遇到通知不显示的问题,可直达 10.1 节。 📌 灵动岛接入参考:【高密级】Alive Status(灵动岛)技术接入文档 📌 通知扩展的 API:通知扩展 API

概述

MiCar 基于原生 Automotive OS 的通知进行了 UI 和部分逻辑的改造,具体业务介绍如下。

1.1 浮动通知

浮动通知位于 HMI 的顶部中间部分,用于展示系统报警与通知,如下图所示。其支持上滑消失,左右滑取消通知,我们可以将其类比为 MIUI 手机上的通知。注意,其区别于具有强交互属性的 dialog(弹窗)。

1.2 通知中心

点击状态栏的通知图标,可以打开通知中心页面,用户在非驾驶状态下可查看非紧急消息以及历史消息的需求,并可查看消息后根据消息提示完成对应操作,包括左右滑动清除通知,一键清除所有通知等操作,如下图所示。

创建通知

下面来介绍如何创建并发送一个基本的通知。

2.1 请求权限

Android 13(T) 及以上版本需要添加权限:

<manifest ...>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <application ...>
        ...
    </application>
</manifest>

Target sdk 在 API 33 以上需要动态申请,或者添加到系统权限白名单。

系统权限白名单位置:

  • DCD:device/micar/common/dcd/default-mi-car-permissions.xml
  • XCD:device/micar/common/system/default-mi-car-permissions.xml

更多参考:通知运行时权限

2.2 创建通知渠道

在 Android O 及以上版本是需要创建通知渠道的,示例代码如下:

NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "渠道名",
        NotificationManager.IMPORTANCE_HIGH);
channel.setSound(uri, audioAttributes); // 如需要可以修改通知提示音,传入 null 会静音
NotificationManagerCompat.from(context).createNotificationChannel(channel);

注意事项:

  1. 渠道 ID 应用自己定义,保证应用内唯一就好。
  2. 如果要显示浮动通知,渠道重要性一定要设置 IMPORTANCE_HIGH 及以上,否则仅会在通知中心显示。
  3. 一旦创建通知渠道后,您将无法更改通知渠道的行为(例如原来有提示音改成静音),除非清理所有数据或删除重建渠道或换一个渠道 id。

更多参考:创建和管理通知渠道

2.3 设置通知内容

您需要使用 NotificationCompat.Builder 对象设置通知内容和渠道。示例代码如下:

NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
        .setCategory(Notification.CATEGORY_CAR_WARNING)
        .setSmallIcon(R.mipmap.ic_launcher) // 必填,一般用 APP 图标
        .setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.ic_car)) // 左侧大图标
        .setContentTitle("标题文本")
        .setContentText("正文文本");

样式如图所示:

其中:

  1. NotificationCompat.Builder 构造函数要求提供渠道 ID。
  2. 有特殊类型需求可以通过 setCategory() 设置一个通知类别,具体要用哪些类别及相关介绍见第 3 节
  3. 必须通过 setSmallIcon() 设置一个小图标(Google SDK 要求),建议使用 APP 图标,但在通知卡片上不会展示出来。
  4. 可以通过 setLargeIcon() 设置左侧的大图标,如果不设置,默认展示应用图标。图片大小可以设定为 90x90dp 或更大。

NotificationCompat.Builder.setLargeIcon(Bitmap icon) 方法只有一个传入 Bitmap 的形式,这样是无法支持图片动态日夜间切换的,如果需要支持日夜间切换,请使用 Notification.BuildersetLargeIcon(Icon icon) 方式构建通知,其中 icon 可使用 Icon.createWithResource() 方法使用图片资源 id。

2.4 设置通知的点按操作

通知也可以响应点按操作,通常是在应用中打开与通知对应的 activity。为此,请指定使用

PendingIntent 对象定义的内容 intent,并将其传递给 setContentIntent()。除了 Activity,还可以实现 BroadcastReceiver 或 Service 执行后台操作。

以下代码段展示了如何创建基本 intent,以便在用户点按通知时打开 activity:

// Create an explicit intent for an Activity in your app.
Intent intent = new Intent(this, AlertDetails.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
 
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        // Set the intent that fires when the user taps the notification.
        .setContentIntent(pendingIntent)
        .setAutoCancel(true);

注意:

  1. 关于 PendingIntent 的使用注意事项可参考文章:https://juejin.cn/post/7122767360976486413,这里写的比较全面,可以避开很多坑。
  2. 如果需要在用户点按通知时自动移除通知,需要调用 setAutoCancel(true)

2.5 添加操作按钮

一个通知最多可以提供三个操作按钮,让用户能够快速响应。如需添加操作按钮,请实现 PendingIntent 并传递给 addAction() 方法。示例代码:

NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
        .setCategory(Notification.CATEGORY_CAR_WARNING)
        .setSmallIcon(R.mipmap.ic_launcher)
        .setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.ic_update))
        .setContentTitle("系统更新") 
        .setContentText("新系统已下载完成,可以更新")
        .addAction(0, "下载更新", pendingIntent1)
        .addAction(0, "稍后", pendingIntent2);

样式如图所示:

注意:

  1. addAction() 方法的第一个参数代表按钮的图标,不需要的话传入 0 就好。
  2. addAction() 方法的第三个参数最好不要传 null,否则将点击没有任何响应。

2.6 显示通知

如需显示通知,请调用 NotificationManagerCompat.notify() 方法,并将通知的唯一 ID 和

NotificationCompat.Builder.build() 的结果传递给它。示例代码:

NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(tag, notificationId, builder.build());

如果是 user 0 的进程,请调用 NotificationManager.notifyAsUser() 方法转到以当前 user 身份执行,示例代码:

NotificationManager notificationManager = (NotificationManager) context.getSystemService(
        Context.NOTIFICATION_SERVICE);
notificationManager.notifyAsUser(tag, notificationId, builder.build(), UserHandle.CURRENT);

请记得保存您传递到 NotificationManagerCompat.notify() 的通知 tag 和 id,因为如果之后您想要更新或移除通知,将需要使用这个 tag 和 id。通知 tag id 由您自己定义,保证应用内唯一就好。

请确保您的应用属于系统特权应用或使用平台密钥签名的应用,否则可能无法触发浮动通知。

以上是创建通知的基本操作,更多通知功能 API 相关使用请参考官方文档:https://developer.android.com/training/notify-user/build-notification?hl=zh-cn

通知类别

目前系统通知类别主要有:智驾提示(即将废弃)、系统状态变更(包含自定义布局)、电话通知和系统应用通知。另外 Alive Status 还有持续活动 P0/P1 类灵动岛提醒类灵动岛

业务方尽量不要使用除这些以外的类别,下面是具体介绍。如果您不能确定您的通知属于哪个类别,可联系产品 @李科男 确认。

目前支持 Category 类型特性快速预览表:

Category类型特性
Notification.CATEGORY_CAR_EMERGENCY(“car_emergency”)该类型已由智驾进行管理,三方应用不允许发送此类型,不进入通知中心。
Notification.CATEGORY_CAR_WARNING(“car_warning”)出现 8s 后主动消失,不进入通知中心
Notification.CATEGORY_CALL通话结束后自动消失,不进入通知中心
Notification.CATEGORY_CAR_INFORMATION(“car_information”)8s 后主动消失,消失后进入通知中心。
HyperNotificationCompat.CATEGORY_CAR_ALIVE_ACTIVE_0持续活动 P0 类通知,消失后进入状态栏
HyperNotificationCompat.CATEGORY_CAR_ALIVE_ACTIVE_1持续活动 P1 类通知,消失后进入状态栏
HyperNotificationCompat.CATEGORY_CAR_ALIVE_REMIND提醒类灵动岛通知,自动消失时不进入状态栏,上滑或被打断进入状态栏

下面是对 category 类型的具体详细介绍:

3.1 智驾提示

图示:

使用场景:智能驾驶相关提示。

特点:不自动消失,由智驾控制消失逻辑。滑动可消失,不进入通知中心。

类型定义Notification.CATEGORY_CAR_EMERGENCY(“car_emergency”)。

Tips:如果因无法直接调用 Notification 定义的类型而编译报错,可直接使用字符串。使用”car_emergency”需要添加权限:

<uses-permission android:name="android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS" />

该类型已由智驾进行管理,三方应用不允许发送此类型。

3.2 系统状态变更与自定义布局通知

3.2.1 系统状态变更

图示:

使用场景:系统提示状态变更时使用的通知。

特点:出现 8s 后主动消失,不进入通知中心。

类型定义Notification.CATEGORY_CAR_WARNING(“car_warning”)。

Tips:如果因无法直接调用 Notification 定义的类型而编译报错,可直接使用字符串。使用”car_warning”需要添加权限:

<uses-permission android:name="android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS" />

3.2.2 自定义布局通知

图示:

使用场景:标准通知布局样式无法满足需求时,可以使用。

特点:用户无操作 8s 后主动消失,不进入通知中心。

类型定义Notification.CATEGORY_CAR_WARNING(“car_warning”)。

Tips:如果因无法直接调用 Notification 定义的类型而编译报错,可直接使用字符串。使用”car_warning”需要添加权限:

<uses-permission android:name="android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS" />

此类型须采用自定义通知实现,调用 setCustomHeadsUpContentView() 方法以设置浮动通知的布局,RemoteViews 支持的类型及使用可参考网址。示例代码:

NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
        .setCategory(Notification.CATEGORY_CAR_WARNING)
        .setSmallIcon(R.drawable.ic_warning)
        .setCustomHeadsUpContentView(remoteViews);

目前宽度是固定的 624dp,高度可变。

3.3 电话通知

图示:

使用场景:电话相关。

特点:通话结束后自动消失,不进入通知中心。

类型定义Notification.CATEGORY_CALL

3.4 系统及系统应用通知

图示:

使用场景:系统以及系统应用的通知。

特点:8s 后主动消失,消失后进入通知中心。

类型定义Notification.CATEGORY_CAR_INFORMATION(“car_information”)。

Tips:如果因无法直接调用 Notification 定义的类型而编译报错,可直接使用字符串。使用”car_information”需要添加权限:

<uses-permission android:name="android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS" />

3.5 灵动岛类型

参考 https://gerrit.auto.mioffice.cn/c/cockpit/core/platform/frameworks/hyperx/+/144733/1/core/core/README-NOTIFICATION.md#14

3.6 互斥逻辑

当前界面正在展示以上某一类通知时,这时要弹出其它类型通知,互斥逻辑如下表所示:

存在出现后台活动类 P0后台活动类 P1提醒类灵动岛系统状态变更电话通知系统及系统应用通知智驾提示(即将废弃)
后台活动类 P0后打断前,前一个进状态栏后打断前,前一个进状态栏后打断前,前一个进状态栏后打断前,前一个消失后打断前,前一个消失后打断前,前一个进通知中心后打断前,前一个消失
后台活动类 P1显示 1,2 进状态栏后打断前,前一个进状态栏后打断前,前一个进状态栏后打断前,前一个消失后打断前,前一个消失后打断前,前一个进通知中心后打断前,前一个消失
提醒类灵动岛后打断前,前一个进状态栏后打断前,前一个进状态栏后打断前,前一个进状态栏后打断前,前一个消失后打断前,前一个消失后打断前,前一个进通知中心后打断前,前一个消失
系统状态变更后打断前,前一个进状态栏后打断前,前一个进状态栏后打断前,前一个进状态栏后打断前,前一个消失后打断前,前一个消失后打断前,前一个进通知中心后打断前,前一个消失
电话通知后打断前,前一个进状态栏后打断前,前一个进状态栏后打断前,前一个进状态栏后打断前,前一个消失后打断前,前一个消失后打断前,前一个进通知中心后打断前,前一个消失
系统及系统应用通知等 1 结束再显示 6后打断前,前一个进状态栏后打断前,前一个进状态栏后打断前,前一个消失等 5 结束再显示 6后打断前,前一个进通知中心等 7 结束再显示 6
智驾提示(即将废弃)后打断前,前一个进状态栏后打断前,前一个进状态栏后打断前,前一个进状态栏后打断前,前一个消失后打断前,前一个消失后打断前,前一个进通知中心后打断前,前一个消失

除上述分类之外的其它分类通知,皆按“系统及系统应用通知”仲裁逻辑处理。

更新通知

如需在发出此通知后对其进行更新,请再次调用 NotificationManagerCompat.notify(),并将之前使用的具有同一 ID 的通知传递给该方法。如果之前的通知已被取消,则系统会创建一个新通知。

您可以选择性调用 setOnlyAlertOnce(),这样通知只会在通知首次显示时弹出浮动通知,以后更新时就不再进行显示。

另外,如果频繁地更新通知,可能有部分通知被丢弃,官方说明如下:https://developer.android.com/develop/ui/views/notifications?hl=zh-cn#limits

移除通知

如需在发出此通知后对其进行移除,请调用 NotificationManagerCompat.cancel(),并将之前使用的具有同一 ID 的通知传递给该方法。

前台服务通知

应用在启用前台服务时默认会发一个通知出来,业务方在构建常规的通知后会出现在通知中心里,并且是一个常驻的通知。为了不影响用户的体验,对用户产生困扰,针对我们系统的应用需要将其隐藏起来。

Android 原生的逻辑是低优先级的系统级应用的前台服务通知是不予展示的,因此业务方只需在构建通知时创建通知渠道(NotificationChannel)的时候将优先级指定为 NotificationManager.IMPORTANCE_LOW 即可,如图:

通知 & 报警中心

7.1 通知中心

通知中心打开方式

可以通过隐式 Intent 打开,

Action 定义:“com.android.car.notification.NOTIFICATION_CENTER”

包名:“com.android.systemui”

示例代码:

Intent intent = new Intent();
intent.setAction("com.android.car.notification.NOTIFICATION_CENTER");
intent.setPackage("com.android.systemui");
context.startActivity(intent);

7.2 报警中心

报警中心打开方式

可以通过隐式 Intent 打开,

Action 定义:“com.android.car.notification.EMERGENCY_CENTER”

包名:“com.android.systemui”

📌 以上所有图示并非最终效果,以视觉稿为主,地址: E4U:https://www.figma.com/file/vnm6w4wKPTBKWGVPq8TkNi/%E9%80%9A%E7%9F%A5%EF%BC%88%E5%AF%B9%E5%A4%96%EF%BC%89 MIUI 1.1:https://www.figma.com/file/VmmjnUFZ9UZb5dt9Oiknhq/%E9%80%9A%E7%9F%A51.1?node-id=1238%3A139973&mode=dev

全局通知提示音开关

public static final String NOTIFICATION_SOUNDS_ENABLED = "mi_notification_sounds_enabled";
Settings.System.getInt(cr, NOTIFICATION_SOUNDS_ENABLED, 1)

值定义:

  • key:mi_notification_sounds_enabled
  • value:0 - 关闭,1 - 开启(默认)

通知相关日志

9.1 framework 日志

以下是 framework 部分打印的日志,可以通过 bugreport 或者 adb logcat -b events 查到。

9.1.1 发送通知

这个日志仅代表业务方调用发送通知的 API 了,不代表一定会弹出:

notification_enqueue: [uid,pid,pkg,id,tag,userid,(notification),status]

其中:

  • notification 代表通知实体信息,日志中以 key-value 形式展示,比较详细,这里不做展开。
  • status 代表通知的发送状态,如图:

9.1.2 取消通知

notification_canceled: [userId|pkg|id|tag|uid,reason,lifespan,freshness,exposure,rank,count,listener]

其中:

  • reason 代表取消通知的原因,所有的原因如下:
/** Notification was canceled by the status bar reporting a notification click. */
public static final int REASON_CLICK = 1;
/** Notification was canceled by the status bar reporting a user dismissal. */
public static final int REASON_CANCEL = 2;
/** Notification was canceled by the status bar reporting a user dismiss all. */
public static final int REASON_CANCEL_ALL = 3;
/** Notification was canceled by the status bar reporting an inflation error. */
public static final int REASON_ERROR = 4;
/** Notification was canceled by the package manager modifying the package. */
public static final int REASON_PACKAGE_CHANGED = 5;
/** Notification was canceled by the owning user context being stopped. */
public static final int REASON_USER_STOPPED = 6;
/** Notification was canceled by the user banning the package. */
public static final int REASON_PACKAGE_BANNED = 7;
/** Notification was canceled by the app canceling this specific notification. */
public static final int REASON_APP_CANCEL = 8;
/** Notification was canceled by the app cancelling all its notifications. */
public static final int REASON_APP_CANCEL_ALL = 9;
/** Notification was canceled by a listener reporting a user dismissal. */
public static final int REASON_LISTENER_CANCEL = 10;
/** Notification was canceled by a listener reporting a user dismiss all. */
public static final int REASON_LISTENER_CANCEL_ALL = 11;
/** Notification was canceled because it was a member of a canceled group. */
public static final int REASON_GROUP_SUMMARY_CANCELED = 12;
/** Notification was canceled because it was an invisible member of a group. */
public static final int REASON_GROUP_OPTIMIZATION = 13;
/** Notification was canceled by the device administrator suspending the package. */
public static final int REASON_PACKAGE_SUSPENDED = 14;
/** Notification was canceled by the owning managed profile being turned off. */
public static final int REASON_PROFILE_TURNED_OFF = 15;
/** Autobundled summary notification was canceled because its group was unbundled */
public static final int REASON_UNAUTOBUNDLED = 16;
/** Notification was canceled by the user banning the channel. */
public static final int REASON_CHANNEL_BANNED = 17;
/** Notification was snoozed. */
public static final int REASON_SNOOZED = 18;
/** Notification was canceled due to timeout */
public static final int REASON_TIMEOUT = 19;
/** Notification was canceled due to the backing channel being deleted */
public static final int REASON_CHANNEL_REMOVED = 20;
/** Notification was canceled due to the app's storage being cleared */
public static final int REASON_CLEAR_DATA = 21;
  • lifespan 代表该通知从第一次发送到现在的毫秒数,忽略中间通知更新的时间。
  • freshness 代表该通知从最近更新的时间(没有更新就是发送时间)到现在的毫秒数。
  • exposure 代表该通知自最近一次可见性事件以来的毫秒数,如果从未发生过,则为 0。
  • rank 代表通知的等级,没有设定就是 -1。
  • listener 代表触发取消通知的监听器的类名,如果没有(例如业务方主动取消的)则为 NULL。

9.1.3 点击通知

notification_clicked: [userId|pkg|id|tag|uid,lifespan,freshness,exposure,rank,count]

其中:

  • lifespan 代表该通知从第一次发送到现在的毫秒数,忽略中间通知更新的时间。
  • freshness 代表该通知从最近更新的时间(没有更新就是发送时间)到现在的毫秒数。
  • exposure 代表该通知自最近一次可见性事件以来的毫秒数,如果从未发生过,则为 0。
  • rank 代表通知的等级,没有设定就是 -1。

9.1.4 点击通知按钮

notification_action_clicked: [userId|pkg|id|tag|uid,action_index,lifespan,freshness,exposure,rank,count]

其中:

  • action_index 代表按钮的索引,从 0 开始。
  • lifespan 代表该通知从第一次发送到现在的毫秒数,忽略中间通知更新的时间。
  • freshness 代表该通知从最近更新的时间(没有更新就是发送时间)到现在的毫秒数。
  • exposure 代表该通知自最近一次可见性事件以来的毫秒数,如果从未发生过,则为 0。
  • rank 代表通知的等级,没有设定就是 -1。

9.1.5 通知开关被关闭

以下日志在 logcat 就可以输出,但需要在开发者选项里把日志级别开到 verbose 并重启。

# 应用的通知开关被关闭了
E NotificationService: Suppressing notification from package [packageName] by user request.

9.2 SystemUI 日志

以下是 SystemUI 部分的 logcat 日志,其中标题就是日志的 TAG。

9.2.1 CarNotificationListener

# 发送通知
onNotificationPosted: key=[userId|pkg|id|tag|uid] channel=[CHANNEL_ID] flags=[flags] category=[category]
# 不是当前用户发的通知
Notification is not for current user: [StatusBarNotification]
Notification user: [userId]
Current user: [userId]
# 通知是否弹出?在下面 CarHeadsUpNotificationManager 判断后打印
Is [userId|pkg|id|tag|uid] shown as HUN?: [true/false]
# 移除通知
onNotiRemove: [userId|pkg|id|tag|uid] channel=[CHANNEL_ID] flags=[flags] category=[category]
# 当前处于禁用通知场景
Forbidden scene is [scene]
# 禁用通知场景发生变化
onNotificationForbiddenChanged: scene = [sceneId], isForbidden = [true/false]
# 进入了通知中心
postNotificationCenter: [userId|pkg|id|tag|uid]

9.2.2 CarHeadsUpNotificationManager

# 判断是否可以弹出通知
Unable to show as HUN: Notification center is showed # 通知中心正在显示
Unable to show as HUN: Forbidden scene is 0xXX # 其它禁用通知的业务场景正在显示
Unable to show as HUN: Keyguard is locked # 正在锁屏,电源是 OFF 或 AWAKE
Unable to show as HUN: OEM has disabled navigation HUN
Unable to show as HUN: Grouping notification
Unable to show as HUN: Messaging notification is muted by user
Unable to show as HUN: importance is not sufficient # importance < IMPORTANCE_HIGH
application is system privileged or signed with platform key # 系统签名应用
Unable to show as HUN: add to pending list # 当前有髙优通知在显示,当前通知加入待显示队列
Show as HUN # 显示浮动通知
# 非系统应用可能输出下面日志
Show as HUN: car messaging type notification
category not set for: [packageName]
Notification category: [category]
# 浮动通知消失
Dismiss for HUN: [userId|pkg|id|tag|uid]
# 禁用通知场景变更
onNotificationForbiddenChanged: scene = 0xXX, isForbidden = true/false

9.2.3 MiCarBeeper

# 相同应用在 1s 内弹出通知,不发声音
Package recently made noise: [packageName]
# 播放提示音
playing sound: [uri]

9.3 dump 日志

除了 logcat 查看实时的通知日志,也可以通过 dump 查询历史通知日志:

adb shell dumpsys notification

Bugreport 中也有部分通知的 dump 信息,搜索关键字“DUMP OF SERVICE CRITICAL notification”可以查询一些关键的通知信息,但并不包含全部的通知;搜索“DUMP OF SERVICE notification”可以查询通知额外的信息,例如通知渠道等等。

Q&A

10.1 浮动通知不显示

浮动通知不显示了怎么办?

大家经常遇到这样的问题,但影响的原因实在太多了,建议大家先仔细自查一下。

10.1.1 代码问题

首先排查一下自己的代码问题:

  1. 通知渠道是否有设置 IMPORTANCE_HIGH 及以上的重要性设置?是否修改过渠道的 importance 属性,如果修改过需要调用 NotificationManagerCompat.deleteNotificationChannel 方法删除一下旧通知渠道再创建,或者创建一个新的渠道 id(之前创建过的渠道谷歌禁止再次修改)。
  2. 在 Android U 及以上版本,是否添加权限 android.permission.POST_NOTIFICATIONS ?有添加过白名单或动态申请吗?白名单位置在 2.1 节。
  3. 您的应用是否属于系统特权应用或使用平台密钥签名的应用?
  4. 使用与 Car 相关的类别是否有添加 android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS 权限?
  5. user0 进程下是否调用 NotificationManager.notifyAsUser() 方法?

10.1.2 运行环境问题

如果确保了以上代码没有问题,看看是不是当前的车机环境存在以下问题:

  1. 确认一下电源模式是不是 OFFAWAKE 状态,这两种模式下通知不会展示(因为与离车显示冲突),可以通过以下命令 mock 修改当前电源模式状态为 ACCRUN
adb root
adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle --mock_from_car 0x61407207 -i 2

最后一个数字是 2 或 3 皆可。

  1. 看下自己的应用的通知开关是不是关了?位置在“设置 - 系统 - 应用管理 - 右上角三个点 - 权限管理 - 通知”。

如果以上条件都满足了,可以看下第 9 节,查看相关日志是否有相关线索。

参考文档