功能和 API 概述

Android 15 为开发者引入了强大的功能和 API。以下部分总结了这些功能,以帮助您开始使用相关的 API。

有关新增、修改和移除 API 的详细列表,请阅读API 差异报告。有关新增 API 的详细信息,请访问Android API 参考——对于 Android 15,请查找 API 级别 35 中新增的 API。要了解平台更改可能影响您应用的领域,请务必查看 Android 15 行为更改针对目标 Android 15 的应用所有应用

相机和媒体

Android 15 包含各种功能,可改善相机和媒体体验,并为您提供工具和硬件,以支持创作者将他们的愿景带到 Android 上。

有关 Android 媒体和相机的最新功能和开发者解决方案的更多信息,请参阅 Google I/O 上的构建现代 Android 媒体和相机体验演讲。

低光增强

Android 15 引入了低光增强,这是一种自动曝光模式,可用于Camera 2夜间模式相机扩展。低光增强可在低光照条件下调整预览流的曝光。这与夜间模式相机扩展创建静态图像的方式不同,因为夜间模式会组合一系列照片以创建单个增强图像。虽然夜间模式非常适合创建静态图像,但它无法创建连续的帧流,而低光增强可以。因此,低光增强可实现相机功能,例如:

  • 提供增强的图像预览,以便用户能够更好地取景低光照照片
  • 在低光照条件下扫描二维码

如果启用低光增强,它会在低光照级别时自动开启,在光线充足时自动关闭。

应用可以在低光照条件下从预览流录制,以保存增亮的视频。

有关更多信息,请参阅低光增强

应用内相机控制

Android 15 为在受支持的设备上更好地控制相机硬件及其算法添加了扩展

  • 高级闪光强度调整可在捕获图像时精确控制SINGLETORCH模式下的闪光强度。

HDR 动态范围控制

Android 15 会选择适合底层设备功能和面板位深的 HDR 动态范围。对于包含大量 SDR 内容的页面(例如显示单个 HDR 缩略图的消息应用),此行为最终可能会对 SDR 内容的感知亮度产生不利影响。Android 15 允许您使用setDesiredHdrHeadroom 控制 HDR 动态范围,以在 SDR 和 HDR 内容之间取得平衡。

左侧屏幕上的 SDR UI 元素的亮度似乎比右侧屏幕的亮度更均匀,这模拟了混合 HDR 和 SDR 内容时可能出现的动态范围问题。通过调整 HDR 动态范围,您可以更好地平衡 SDR 和 HDR 内容。

响度控制

Android 15 引入了对CTA-2075 响度标准的支持,以帮助您避免音频响度不一致,并确保用户在切换内容时无需不断调整音量。系统利用输出设备(耳机和扬声器)的已知特性以及 AAC 音频内容中可用的响度元数据,智能地调整音频响度和动态范围压缩级别。

要启用此功能,您需要确保 AAC 内容中提供响度元数据,并在您的应用中启用平台功能。为此,您可以通过调用其 LoudnessCodecController 对象的 create 工厂方法(使用关联的 AudioTrack 的音频会话 ID)来实例化一个 LoudnessCodecController 对象;这会自动开始应用音频更新。您可以传递一个 OnLoudnessCodecUpdateListener 来修改或过滤响度参数,然后再将它们应用于 MediaCodec

// Media contains metadata of type MPEG_4 OR MPEG_D
val mediaCodec = 
val audioTrack = AudioTrack.Builder()
                                .setSessionId(sessionId)
                                .build()
...
// Create new loudness controller that applies the parameters to the MediaCodec
try {
   val lcController = LoudnessCodecController.create(mSessionId)
   // Starts applying audio updates for each added MediaCodec
}

AndroidX media3 ExoPlayer 也将更新为使用 LoudnessCodecController API,以实现无缝的应用集成。

虚拟 MIDI 2.0 设备

Android 13 添加了对使用 USB 连接 MIDI 2.0 设备 的支持,这些设备使用通用 MIDI 数据包 (UMP) 进行通信。Android 15 将 UMP 支持扩展到虚拟 MIDI 应用,使作曲应用能够像使用 USB MIDI 2.0 设备一样控制合成器应用作为虚拟 MIDI 2.0 设备。

更高效的 AV1 软件解码

dav1d logo

来自 VideoLAN 的流行 AV1 软件解码器 dav1d 可用于不支持硬件 AV1 解码的 Android 设备。dav1d 的性能比旧版 AV1 软件解码器高出 3 倍,使更多用户能够播放高清 AV1 视频,包括一些低端和中端设备。

您的应用需要通过名称 "c2.android.av1-dav1d.decoder" 调用它来选择使用 dav1d。在后续更新中,dav1d 将成为默认的 AV1 软件解码器。此支持已标准化并向接收 Google Play 系统更新的 Android 11 设备回传。

开发者生产力和工具

虽然我们大部分提高您生产力的工作都围绕着 Android StudioJetpack ComposeAndroid Jetpack 库等工具展开,但我们一直在寻找平台上的方法来帮助您更轻松地实现您的愿景。

OpenJDK 17 更新

Android 15 继续刷新 Android 的核心库的工作,使其与最新 OpenJDK LTS 版本中的功能保持一致。

包含以下关键功能和改进

这些 API 通过 Google Play 系统更新在 运行 Android 12(API 级别 31)及更高版本的十多亿台设备上更新,因此您可以定位最新的编程功能。

PDF 改进

Android 15 包含对 PdfRenderer API 的重大改进。应用可以合并高级功能,例如渲染 受密码保护的文件、注释、表单编辑搜索 和带有复制功能的 选择。支持线性化 PDF 优化,以加快本地 PDF 查看速度并减少资源使用。Jetpack PDF 库 使用这些 API 来简化向您的应用添加 PDF 查看功能。

PDF 渲染的最新更新包括搜索嵌入式 PDF 文件等功能。

PdfRenderer 已移至一个模块,该模块可以使用 Google Play 系统更新独立于平台版本进行更新,并且我们通过创建 API 表面的兼容 Android 15 之前的版本 PdfRendererPreV 来支持这些更改回传到 Android 11(API 级别 30)。

自动语言切换改进

Android 14 在音频中添加了设备上的多语言识别,并支持在语言之间自动切换,但这可能会导致单词丢失,尤其是在两种语言之间切换时暂停时间较短的情况下。Android 15 添加了其他控件,以帮助应用根据其用例调整此切换。EXTRA_LANGUAGE_SWITCH_INITIAL_ACTIVE_DURATION_TIME_MILLIS 将自动切换限制在音频会话的开头,而 EXTRA_LANGUAGE_SWITCH_MATCH_SWITCHES 在定义的切换次数后停用语言切换。如果您预计会话期间只会说一种应自动检测的语言,则这些选项特别有用。

改进的 OpenType 可变字体 API

Android 15 提高了 OpenType 可变字体的可用性。您可以使用 buildVariableFamily API 从可变字体创建 FontFamily 实例,无需指定权重轴。文本渲染器会覆盖 wght 轴的值以匹配显示文本。

使用此 API 可以大大简化创建 Typeface 的代码

Kotlin

val newTypeface = Typeface.CustomFallbackBuilder(
            FontFamily.Builder(
                Font.Builder(assets, "RobotoFlex.ttf").build())
                    .buildVariableFamily())
    .build()

Java

Typeface newTypeface = Typeface.CustomFallbackBuilder(
            new FontFamily.Builder(
                new Font.Builder(assets, "RobotoFlex.ttf").build())
                    .buildVariableFamily())
    .build();

以前,要创建相同的 Typeface,需要更多代码

Kotlin

val oldTypeface = Typeface.CustomFallbackBuilder(
            FontFamily.Builder(
                Font.Builder(assets, "RobotoFlex.ttf")
                    .setFontVariationSettings("'wght' 400")
                    .setWeight(400)
                    .build())
                .addFont(
                    Font.Builder(assets, "RobotoFlex.ttf")
                        .setFontVariationSettings("'wght' 100")
                        .setWeight(100)
                        .build()
                )
                .addFont(
                    Font.Builder(assets, "RobotoFlex.ttf")
                        .setFontVariationSettings("'wght' 200")
                        .setWeight(200)
                        .build()
                )
                .addFont(
                    Font.Builder(assets, "RobotoFlex.ttf")
                        .setFontVariationSettings("'wght' 300")
                        .setWeight(300)
                        .build()
                )
                .addFont(
                    Font.Builder(assets, "RobotoFlex.ttf")
                        .setFontVariationSettings("'wght' 500")
                        .setWeight(500)
                        .build()
                )
                .addFont(
                    Font.Builder(assets, "RobotoFlex.ttf")
                        .setFontVariationSettings("'wght' 600")
                        .setWeight(600)
                        .build()
                )
                .addFont(
                    Font.Builder(assets, "RobotoFlex.ttf")
                        .setFontVariationSettings("'wght' 700")
                        .setWeight(700)
                        .build()
                )
                .addFont(
                    Font.Builder(assets, "RobotoFlex.ttf")
                        .setFontVariationSettings("'wght' 800")
                        .setWeight(800)
                        .build()
                )
                .addFont(
                    Font.Builder(assets, "RobotoFlex.ttf")
                        .setFontVariationSettings("'wght' 900")
                        .setWeight(900)
                        .build()
                ).build()
        ).build()

Java

Typeface oldTypeface = new Typeface.CustomFallbackBuilder(
    new FontFamily.Builder(
        new Font.Builder(assets, "RobotoFlex.ttf")
            .setFontVariationSettings("'wght' 400")
            .setWeight(400)
            .build()
    )
    .addFont(
        new Font.Builder(assets, "RobotoFlex.ttf")
            .setFontVariationSettings("'wght' 100")
            .setWeight(100)
            .build()
    )
    .addFont(
        new Font.Builder(assets, "RobotoFlex.ttf")
            .setFontVariationSettings("'wght' 200")
            .setWeight(200)
            .build()
    )
    .addFont(
        new Font.Builder(assets, "RobotoFlex.ttf")
            .setFontVariationSettings("'wght' 300")
            .setWeight(300)
            .build()
    )
    .addFont(
        new Font.Builder(assets, "RobotoFlex.ttf")
            .setFontVariationSettings("'wght' 500")
            .setWeight(500)
            .build()
    )
    .addFont(
        new Font.Builder(assets, "RobotoFlex.ttf")
            .setFontVariationSettings("'wght' 600")
            .setWeight(600)
            .build()
    )
    .addFont(
        new Font.Builder(assets, "RobotoFlex.ttf")
            .setFontVariationSettings("'wght' 700")
            .setWeight(700)
            .build()
    )
    .addFont(
        new Font.Builder(assets, "RobotoFlex.ttf")
            .setFontVariationSettings("'wght' 800")
            .setWeight(800)
            .build()
    )
    .addFont(
        new Font.Builder(assets, "RobotoFlex.ttf")
            .setFontVariationSettings("'wght' 900")
            .setWeight(900)
            .build()
    )
    .build()
).build();

这是一个使用旧版和新版 API 创建的 Typeface 的渲染示例

An example of how Typeface rendering differs using new and old
APIs

在此示例中,使用旧版 API 创建的 Typeface 无法为 350、450、550 和 650 Font 实例创建准确的字体权重,因此渲染器会回退到最接近的权重。因此,在这种情况下,会渲染 300 而不是 350,渲染 400 而不是 450,依此类推。相比之下,使用新版 API 创建的 Typeface 会为给定权重动态创建 Font 实例,因此也会为 350、450、550 和 650 渲染准确的权重。

细粒度的换行控制

从 Android 15 开始,TextView 和底层换行器可以保留文本的给定部分在同一行中,以提高可读性。您可以通过在字符串资源中使用 <nobreak> 标记或 createNoBreakSpan 来利用此换行自定义。类似地,您可以通过使用 <nohyphen> 标记或 createNoHyphenationSpan 来保留单词免于断字。

例如,以下字符串资源不包含换行符,并且“Pixel 8 Pro.”文本在不理想的位置换行

<resources>
    <string name="pixel8pro">The power and brains behind Pixel 8 Pro.</string>
</resources>

相反,此字符串资源包含 <nobreak> 标记,该标记包装短语“Pixel 8 Pro.”并防止换行

<resources>
    <string name="pixel8pro">The power and brains behind <nobreak>Pixel 8 Pro.</nobreak></string>
</resources>

这些字符串的渲染方式差异如下图所示

一行文本的布局,其中短语“Pixel 8 Pro.”未使用 <nobreak> 标记进行换行。
使用 <nobreak> 标记换行同一行文本的布局。

应用归档

Android 和 Google Play 去年宣布支持应用归档,允许用户通过从设备中部分删除使用 Android 应用包在 Google Play 上发布的不经常使用的应用来释放空间。Android 15 包含对应用归档和取消归档的操作系统级支持,使所有应用商店更容易实现它。

具有 REQUEST_DELETE_PACKAGES 权限的应用可以调用 PackageInstallerrequestArchive 方法来请求归档已安装的应用包,这将删除 APK 和任何缓存文件,但会保留用户数据。归档的应用通过 LauncherApps API 作为可显示的应用返回;用户将看到一个 UI 处理,以突出显示这些应用已归档。如果用户点击归档的应用,相应的安装程序将收到一个请求来 取消归档 它,并且可以通过 ACTION_PACKAGE_ADDED 广播监控恢复过程。

图形

Android 15 带来了最新的图形改进,包括 ANGLE 和对 Canvas 图形系统的补充。

现代化 Android 的 GPU 访问

Vulkan logo

Android 硬件与早期核心操作系统在单个 CPU 上运行且使用基于固定功能管道的 API 访问 GPU 的情况相比已经发生了很大变化。Vulkan® 图形 API 自 Android 7.0(API 级别 24)以来就已在 NDK 中可用,它具有更低级别的抽象,更能反映现代 GPU 硬件,更好地扩展以支持多个 CPU 内核,并降低了 CPU 驱动程序开销,从而提高了应用性能。Vulkan 受所有现代游戏引擎的支持。

Vulkan 是 Android 首选的 GPU 接口。因此,Android 15 包括 ANGLE 作为在 Vulkan 之上运行 OpenGL® ES 的可选层。转向 ANGLE 将使 Android OpenGL 实现标准化,从而提高兼容性,并在某些情况下提高性能。您可以通过启用开发人员选项来测试 OpenGL ES 应用的稳定性和性能:在 Android 15 上的**设置 -> 系统 -> 开发人员选项 -> 实验性:启用 ANGLE**。

基于 Vulkan 的 Android ANGLE 路线图

Roadmap of upcoming changes to the Android GPU APIs.

作为简化 GPU 堆栈的一部分,未来我们将继续在更多新设备上将 ANGLE 作为 GL 系统驱动程序提供,未来预计 OpenGL/ES 将仅通过 ANGLE 提供。也就是说,我们计划**继续支持所有设备上的 OpenGL ES**。

推荐的后续步骤

使用开发人员选项为 OpenGL ES 选择 ANGLE 驱动程序并测试您的应用。对于新项目,我们强烈建议使用 Vulkan(针对 C/C++)。

Canvas 的改进

Android 15 继续对 Android 的 Canvas 图形系统进行现代化改造,并增加了更多功能。

  • Matrix44 提供了一个 4x4 矩阵,用于转换坐标,当您想要在 3D 环境下操作画布时应该使用它。
  • clipShader 将当前剪裁区域与指定的着色器相交,而 clipOutShader 将剪裁区域设置为当前剪裁区域与着色器的差集,两者都将着色器视为 alpha 遮罩。这支持高效绘制复杂形状。

性能和电池

Android 继续专注于帮助您提高应用的性能和质量。Android 15 引入了 API,有助于提高应用中任务的执行效率、优化应用性能以及收集有关应用的见解。

有关电池效率最佳实践、调试网络和电源使用情况以及我们如何改进 Android 15 和最新 Android 版本中后台工作的电池效率的详细信息,请参阅 Google I/O 的 改进 Android 上后台工作的电池效率 演讲。

ApplicationStartInfo API

在之前的 Android 版本中,应用启动一直有点神秘。很难在应用内确定它是从冷启动、温启动还是热启动状态启动的。也很难知道应用在各个启动阶段(例如,创建进程、调用 onCreate、绘制第一帧等)花费了多长时间。当您的 Application 类实例化时,您无法知道应用是从广播、内容提供程序、作业、备份、启动完成、闹钟还是 Activity 启动的。

Android 15 上的 ApplicationStartInfo API 提供了所有这些信息以及更多内容。您甚至可以选择将自己的时间戳添加到流程中,以帮助在一个地方收集计时数据。除了收集指标外,您还可以使用 ApplicationStartInfo 直接优化应用启动;例如,当应用因广播而启动时,您可以消除在 Application 类中实例化与 UI 相关的库的高昂成本。

详细的应用大小信息

自 Android 8.0(API 级别 26)以来,Android 就包含了 StorageStats.getAppBytes API,该 API 将应用的安装大小汇总为单个字节数,这是 APK 大小、从 APK 中提取的文件大小以及设备上生成的文件(例如提前编译 (AOT) 代码)的总和。就您的应用如何使用存储空间而言,此数字并没有什么特别的意义。

Android 15 添加了 StorageStats.getAppBytesByDataType([type]) API,它允许您深入了解您的应用如何占用所有这些空间,包括 APK 文件拆分、AOT 和加速相关的代码、dex 元数据、库和引导配置文件。

应用管理的性能分析

Android 15 包含 ProfilingManager 类,它允许您从应用内收集性能分析信息,例如堆转储、堆配置文件、堆栈采样等。它向您的应用提供带有提供的标签的回调以标识输出文件,该文件将传递到您的应用的文件目录。该 API 会进行速率限制,以最大限度地减少性能影响。

为了简化在应用中构建性能分析请求,我们建议使用相应的 Profiling AndroidX API,该 API 可在 Core 1.15.0-rc01 或更高版本中使用。

SQLite 数据库改进

Android 15 引入了 SQLite API,这些 API 公开了底层 SQLite 引擎的高级功能,这些功能针对应用中可能出现的特定性能问题。这些 API 包含在 SQLite 更新到 3.44.3 版本 中。

开发人员应查阅 SQLite 性能最佳实践 以充分利用其 SQLite 数据库,尤其是在处理大型数据库或运行延迟敏感查询时。

  • **只读延迟事务:** 当发出只读事务(不包含写语句)时,使用 beginTransactionReadOnly()beginTransactionWithListenerReadOnly(SQLiteTransactionListener) 来发出只读 DEFERRED 事务。此类事务可以彼此并发运行,如果数据库处于 WAL 模式,则它们可以与 IMMEDIATEEXCLUSIVE 事务并发运行。
  • **行数和 ID:** 添加了 API 来检索已更改的行数或最后插入的行 ID,无需发出其他查询。getLastChangedRowCount() 返回当前事务中最新的 SQL 语句插入、更新或删除的行数,而 getTotalChangedRowCount() 返回当前连接上的计数。getLastInsertRowId() 返回当前连接上插入的最后一行 rowid
  • **原始语句:** 发出原始 SQlite 语句,绕过便捷包装器以及它们可能产生的任何额外处理开销。

Android 动态性能框架更新

Android 15 继续投资 Android 动态性能框架 (ADPF),这是一个 API 集,允许游戏和性能密集型应用更直接地与 Android 设备的电源和热系统进行交互。在支持的设备上,Android 15 添加了 ADPF 功能。

  • 提示会话的 节能模式 用于指示其关联线程应优先考虑省电而不是性能,非常适合长时间运行的后台工作负载。
  • GPU 和 CPU 工作持续时间都可以在提示会话中 报告,允许系统同时调整 CPU 和 GPU 频率以最佳满足工作负载需求。
  • 热裕量阈值 用于根据裕量预测来解释可能的热节流状态。

要了解如何在您的应用和游戏中使用 ADPF,请访问文档

隐私

Android 15 包含各种功能,可帮助应用开发人员保护用户隐私。

屏幕录制检测

Android 15 添加了 对应用的支持,以检测它们是否正在被录制。每当应用在屏幕录制中可见或不可见之间转换时,都会调用回调。如果注册进程的 UID 拥有的活动正在被录制,则应用被认为是可见的。这样,如果您的应用正在执行敏感操作,您可以告知用户他们正在被录制。

val mCallback = Consumer<Int> { state ->
  if (state == SCREEN_RECORDING_STATE_VISIBLE) {
    // We're being recorded
  } else {
    // We're not being recorded
  }
}

override fun onStart() {
   super.onStart()
   val initialState =
      windowManager.addScreenRecordingCallback(mainExecutor, mCallback)
   mCallback.accept(initialState)
}

override fun onStop() {
    super.onStop()
    windowManager.removeScreenRecordingCallback(mCallback)
}

扩展的 IntentFilter 功能

Android 15 通过 UriRelativeFilterGroup 内置了对更精确 Intent 解析的支持,它包含一组 UriRelativeFilter 对象,这些对象构成一组必须每个都满足的 Intent 匹配规则,包括 URL 查询参数、URL 片段以及阻止或排除规则。

这些规则可以在 AndroidManifest XML 文件中使用 <uri-relative-filter-group> 标签定义,该标签可以选择包含 android:allow 标签。这些标签可以包含使用现有数据标签属性以及 android:queryandroid:fragment 属性的 <data> 标签。

这是一个 AndroidManifest 语法的示例

<intent-filter>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.BROWSABLE" />
  <category android:name="android.intent.category.DEFAULT" />
  <data android:scheme="http" />
  <data android:scheme="https" />
  <data android:domain="astore.com" />
  <uri-relative-filter-group>
    <data android:pathPrefix="/auth" />
    <data android:query="region=na" />
  </uri-relative-filter-group>
  <uri-relative-filter-group android:allow="false">
    <data android:pathPrefix="/auth" />
    <data android:query="mobileoptout=true" />
  </uri-relative-filter-group>
  <uri-relative-filter-group android:allow="false">
    <data android:pathPrefix="/auth" />
    <data android:fragmentPrefix="faq" />
  </uri-relative-filter-group>
</intent-filter>

私密空间

可以解锁和锁定私密空间以显示或隐藏设备上的敏感应用。

私密空间允许用户在其设备上创建一个单独的空间,他们可以在其中将敏感应用与窥探的眼睛隔离开来,并增加一层身份验证。私密空间使用单独的用户配置文件。用户可以选择使用设备锁或单独的锁因子来保护私密空间。

私密空间中的应用在启动器中显示在单独的容器中,并在私密空间锁定后隐藏在最近使用的视图、通知、设置和其他应用中。用户生成和下载的内容(例如媒体或文件)以及帐户在私密空间和主空间之间是分开的。当私密空间解锁时,可以使用 系统共享表照片选择器 来允许应用访问跨空间的内容。

用户无法将现有应用及其数据移动到私密空间。相反,用户可以选择私密空间中的安装选项,使用他们喜欢的任何应用商店安装应用。私密空间中的应用是从主空间中的任何应用安装的单独副本(同一应用的新副本)。

当用户锁定私密空间时,配置文件将停止。在配置文件停止时,私密空间中的应用将不再活动,并且无法执行前台或后台活动,包括显示通知。

我们建议您使用私有空间测试您的应用,以确保其按预期运行,尤其是在您的应用属于以下类别之一的情况下

查询最近用户选择的“已选择照片”访问权限

当授予对媒体权限的部分访问权限时,应用现在可以仅突出显示最近选择的图片和视频。此功能可以改善频繁请求访问照片和视频的应用的用户体验。要在您的应用中使用此功能,请在通过ContentResolver查询MediaStore时启用QUERY_ARG_LATEST_SELECTION_ONLY参数。

Kotlin

val externalContentUri = MediaStore.Files.getContentUri("external")

val mediaColumns = arrayOf(
   FileColumns._ID,
   FileColumns.DISPLAY_NAME,
   FileColumns.MIME_TYPE,
)

val queryArgs = bundleOf(
   // Return only items from the last selection (selected photos access)
   QUERY_ARG_LATEST_SELECTION_ONLY to true,
   // Sort returned items chronologically based on when they were added to the device's storage
   QUERY_ARG_SQL_SORT_ORDER to "${FileColumns.DATE_ADDED} DESC",
   QUERY_ARG_SQL_SELECTION to "${FileColumns.MEDIA_TYPE} = ? OR ${FileColumns.MEDIA_TYPE} = ?",
   QUERY_ARG_SQL_SELECTION_ARGS to arrayOf(
       FileColumns.MEDIA_TYPE_IMAGE.toString(),
       FileColumns.MEDIA_TYPE_VIDEO.toString()
   )
)

Java

Uri externalContentUri = MediaStore.Files.getContentUri("external");

String[] mediaColumns = {
    FileColumns._ID,
    FileColumns.DISPLAY_NAME,
    FileColumns.MIME_TYPE
};

Bundle queryArgs = new Bundle();
queryArgs.putBoolean(MediaStore.QUERY_ARG_LATEST_SELECTION_ONLY, true);
queryArgs.putString(MediaStore.QUERY_ARG_SQL_SORT_ORDER, FileColumns.DATE_ADDED + " DESC");
queryArgs.putString(MediaStore.QUERY_ARG_SQL_SELECTION, FileColumns.MEDIA_TYPE + " = ? OR " + FileColumns.MEDIA_TYPE + " = ?");
queryArgs.putStringArray(MediaStore.QUERY_ARG_SQL_SELECTION_ARGS, new String[] {
    String.valueOf(FileColumns.MEDIA_TYPE_IMAGE),
    String.valueOf(FileColumns.MEDIA_TYPE_VIDEO)
});

Android上的隐私沙盒

Android 15包含最新的Android广告服务扩展,其中包含最新版本的Android上的隐私沙盒。此新增功能是我们开发技术的组成部分,这些技术可以提高用户隐私,并为移动应用提供有效且个性化的广告体验。我们的隐私沙盒页面提供了有关Android隐私沙盒开发者预览版和测试版程序的更多信息,以帮助您入门。

健康连接

Android 15集成了围绕Android的健康连接的最新扩展,这是一个安全且集中的平台,用于管理和共享应用收集的健康和健身数据。此更新增加了对健身营养、皮肤温度、训练计划等更多数据类型的支持。

皮肤温度跟踪允许用户从可穿戴设备或其他跟踪设备存储和共享更准确的温度数据。

训练计划是有结构的锻炼计划,可帮助用户实现其健身目标。训练计划支持包括各种完成和性能目标。

要了解有关Android中健康连接最新更新的更多信息,请参阅Google I/O上的使用Android Health构建自适应体验主题演讲。

部分屏幕共享

Android 15支持部分屏幕共享,因此用户可以共享或录制应用程序窗口而不是整个设备屏幕。此功能(首次在Android 14 QPR2中启用)包括MediaProjection回调,允许您的应用自定义部分屏幕共享体验。请注意,对于目标为Android 14(API级别34)或更高的应用,每次MediaProjection捕获会话都需要用户同意

用户体验和系统UI

Android 15让应用开发者和用户可以更灵活地控制和配置其设备以满足其需求。

要了解有关如何使用Android 15中的最新改进以改善您的应用用户体验的更多信息,请参阅Google I/O上的改进您的Android应用的用户体验主题演讲。

使用生成的预览 API 提供更丰富的窗口小部件预览

在Android 15之前,提供窗口小部件选择器预览的唯一方法是指定静态的图像或布局资源。这些预览通常与窗口小部件放置在主屏幕上的实际外观差异很大。此外,静态资源无法使用Jetpack Glance创建,因此Glance开发者必须对其窗口小部件进行截图或创建XML布局才能拥有窗口小部件预览。

Android 15增加了对生成预览的支持。这意味着应用窗口小部件提供程序可以生成RemoteViews用作选择器预览,而不是静态资源。

应用可以向窗口小部件选择器提供Remote Views,因此它们可以更新选择器中的内容,使其更能代表用户将看到的内容。

推送API

应用可以通过推送API提供生成的预览。应用可以在其生命周期的任何时间点提供预览,并且不会收到主机的显式请求来提供预览。预览会保存在AppWidgetService中,主机可以按需请求它们。以下示例加载XML窗口小部件布局资源并将其设置为预览。

AppWidgetManager.getInstance(appContext).setWidgetPreview(
   ComponentName(
       appContext,
       SociaLiteAppWidgetReceiver::class.java
   ),
   AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN,
   RemoteViews("com.example", R.layout.widget_preview)
)

预期的流程是

  1. 在任何时候,窗口小部件提供程序都会调用setWidgetPreview。提供的预览会与其他提供程序信息一起保存在AppWidgetService中。
  2. setWidgetPreview通过AppWidgetHost.onProvidersChanged回调通知主机已更新的预览。作为响应,窗口小部件主机将重新加载其所有提供程序信息。
  3. 在显示窗口小部件预览时,主机会检查AppWidgetProviderInfo.generatedPreviewCategories,如果选择的类别可用,则调用AppWidgetManager.getWidgetPreview来返回此提供程序的已保存预览。

何时调用setWidgetPreview

由于没有提供预览的回调,因此应用可以选择在其运行的任何时间点发送预览。更新预览的频率取决于窗口小部件的使用情况。

以下列表描述了预览使用案例的两个主要类别

  • 在窗口小部件预览中显示真实数据的提供程序,例如个性化信息或最近的信息。这些提供程序可以在用户登录或在其应用中完成初始配置后设置预览。在此之后,他们可以设置定期任务以按照其选择的节奏更新预览。此类窗口小部件的示例可能是照片、日历、天气或新闻窗口小部件。
  • 在预览中显示静态信息或不显示任何数据的快速操作窗口小部件的提供程序。这些提供程序可以在应用首次启动时设置预览。此类窗口小部件的示例包括驱动器快速操作窗口小部件或Chrome快捷方式窗口小部件。

某些提供程序可能会在中心模式选择器中显示静态预览,但在主屏幕选择器中显示真实信息。这些提供程序应遵循这两个用例的指南来设置预览。

画中画

Android 15对画中画 (PiP) 进行了更改,确保在进入PiP模式时过渡更加流畅。这对于在主UI之上叠加UI元素的应用进入PiP模式将非常有益。

开发者使用onPictureInPictureModeChanged回调来定义切换叠加UI元素可见性的逻辑。此回调会在PiP进入或退出动画完成后触发。从Android 15开始,PictureInPictureUiState类包含另一个状态。

使用此UI状态,目标为Android 15(API级别35)的应用将在PiP动画开始时观察到Activity#onPictureInPictureUiStateChanged回调被调用,其中isTransitioningToPip()为true。当应用处于PiP模式时,许多UI元素与应用无关,例如包含建议、即将播放的视频、评分和标题等信息的视图或布局。当应用进入PiP模式时,使用onPictureInPictureUiStateChanged回调隐藏这些UI元素。当应用从PiP窗口进入全屏模式时,使用onPictureInPictureModeChanged回调显示这些元素,如下例所示。

override fun onPictureInPictureUiStateChanged(pipState: PictureInPictureUiState) {
        if (pipState.isTransitioningToPip()) {
          // Hide UI elements
        }
    }
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) {
        if (isInPictureInPictureMode) {
          // Unhide UI elements
        }
    }

这种无关UI元素(对于PiP窗口)的快速可见性切换有助于确保更流畅且无闪烁的PiP进入动画。

改进的请勿打扰规则

AutomaticZenRule允许应用自定义注意力管理(请勿打扰)规则并决定何时激活或停用它们。Android 15极大地增强了这些规则,目标是改善用户体验。包含以下增强功能:

  • AutomaticZenRule添加类型,允许系统对某些规则应用特殊处理。
  • AutomaticZenRule添加图标,有助于使模式更易于识别。
  • AutomaticZenRule添加triggerDescription字符串,描述规则应为用户激活的条件。
  • AutomaticZenRule添加了ZenDeviceEffects,允许规则触发诸如灰度显示、夜间模式或调暗壁纸等操作。

为通知渠道设置VibrationEffect

Android 15 支持使用 NotificationChannel.setVibrationEffect 为每个渠道的来电通知设置丰富的振动效果,以便用户无需查看设备即可区分不同类型的通知。

媒体投射状态栏芯片和自动停止

媒体投射可能会泄露用户的隐私信息。新的醒目状态栏芯片会提醒用户当前是否有屏幕投射正在进行。用户可以点击该芯片停止屏幕投射、共享或录制。此外,为了提供更直观的用户体验,当设备屏幕锁定后,任何正在进行的屏幕投射都会自动停止。

屏幕共享、投射和录制的状体栏芯片。

大屏幕和多种设备形态

Android 15 为您的应用提供了充分利用 Android 设备形态的支持,包括大屏幕、翻盖式和折叠式设备。

改进的大屏幕多任务处理

Android 15 为用户提供了在大屏幕设备上进行多任务处理的更好方法。例如,用户可以保存他们最喜欢的分屏应用组合以方便快速访问,并可将任务栏固定在屏幕上以便快速切换应用。这意味着确保您的应用具有自适应性比以往任何时候都更重要。

Google I/O 提供了关于 构建自适应 Android 应用使用 Material 3 自适应库构建 UI 的会议,我们的文档还提供了更多帮助您 为大屏幕设计 的信息。

保护屏幕支持

您的应用可以 声明一个属性,Android 15 使用该属性允许您的 ApplicationActivity 在支持的翻盖式设备的小型保护屏幕上显示。这些屏幕太小,无法被视为 Android 应用运行的兼容目标,但您的应用可以选择支持它们,从而使您的应用可在更多地方使用。

连接

Android 15 更新了平台,使您的应用能够访问通信和无线技术的最新进展。

卫星支持

Android 15 继续扩展对卫星连接的平台支持,并包含一些 UI 元素以确保在卫星连接环境中提供一致的用户体验。

应用可以使用 ServiceState.isUsingNonTerrestrialNetwork() 检测设备何时连接到卫星,从而使其更了解为什么完整网络服务可能不可用。此外,Android 15 还支持短信和彩信应用以及预加载的 RCS 应用使用卫星连接发送和接收消息。

设备连接到卫星时会显示通知。

更流畅的 NFC 体验

Android 15 致力于使“轻触支付”体验更无缝、更可靠,同时继续支持 Android 强大的 NFC 应用生态系统。在支持的设备上,应用可以请求 NfcAdapter 进入 观察模式,在该模式下,设备会监听但不会响应 NFC 读卡器,并将应用的 NFC 服务 PollingFrame 对象 发送到处理程序。 PollingFrame 对象可用于在与 NFC 读卡器进行首次通信之前进行身份验证,在许多情况下允许一次轻触完成交易。

此外,应用可以在支持的设备上 注册过滤器,以便它们可以收到轮询循环活动的通知,从而允许与多个支持 NFC 的应用程序顺利运行。

钱包角色

Android 15 引入了一个钱包角色,允许与用户的首选钱包应用更紧密地集成。此角色取代了 NFC 默认的非接触式支付设置。用户可以通过导航到**设置 > 应用 > 默认应用**来管理钱包角色持有者。

此角色用于在为支付类别中注册的 AID 路由 NFC 轻触时使用。轻触操作始终会传递给钱包角色持有者,除非另一个为同一 AID 注册的应用正在前台运行。

此角色还用于确定激活时钱包快速访问磁贴的位置。当角色设置为“无”时,快速访问磁贴不可用,并且支付类别 NFC 轻触操作仅传递给前台应用。

安全

Android 15 可帮助您增强应用的安全性,保护应用数据,并为用户提供更多关于其数据的透明度和控制权。请参阅 Google I/O 上关于 保护 Android 上的用户安全 的演讲,以了解我们为改进用户保护措施并保护您的应用免受新的威胁所做的更多努力。

将凭据管理器与自动填充集成

从 Android 15 开始,开发人员可以 将特定视图(如用户名或密码字段)与凭据管理器请求链接,从而更轻松地在登录过程中提供量身定制的用户体验。当用户将焦点放在这些视图之一上时,相应的请求将发送到凭据管理器。生成的凭据将在提供商之间进行汇总,并在自动填充后备 UI(例如内联建议或下拉建议)中显示。Jetpack androidx.credentials 库是开发人员首选的端点,并且很快就会可用,以进一步增强 Android 15 及更高版本中的此功能。

将单点登录和单点注册与生物识别提示集成

凭据管理器 将生物识别提示集成到凭据创建和登录过程中,无需提供商管理生物识别提示。因此,凭据提供商只需要关注创建和获取流程的结果,并增加生物识别流程的结果。此简化流程创建了更高效、更精简的凭据创建和检索流程。

端到端加密的关键管理

我们在 Android 15 中引入了 E2eeContactKeysManager,它通过提供用于存储加密公钥的操作系统级 API 来促进 Android 应用中的端到端加密 (E2EE)。

E2eeContactKeysManager 旨在与平台联系人应用集成,为用户提供集中管理和验证其联系人公钥的方法。

内容 URI 的权限检查

Android 15 引入了一组 API,用于对内容 URI 执行权限检查。

辅助功能

Android 15 添加了可改善用户辅助功能的功能。

更好的盲文支持

在 Android 15 中,我们使 TalkBack 可以支持通过 USB 和安全蓝牙使用 HID 标准的盲文显示器。

与鼠标和键盘使用的标准类似,此标准将有助于 Android 随着时间的推移支持更广泛的盲文显示器。

国际化

Android 15 添加了一些功能和特性,可以提升设备在不同语言环境下的用户体验。

中日韩 (CJK) 可变字体

从 Android 15 开始,中文、日文和韩文 (CJK) 语言的字体文件 NotoSansCJK 现在是可变字体。可变字体为 CJK 语言的创意排版提供了更多可能性。设计师可以探索更广泛的样式,并创建以前难以实现或无法实现的视觉效果引人注目的布局。

中文、日文和韩文 (CJK) 语言的可变字体在不同字体宽度下的显示效果。

字间对齐

从 Android 15 开始,可以使用 JUSTIFICATION_MODE_INTER_CHARACTER 通过使用字母间距来对齐文本。字间对齐功能最早在 Android 8.0(API 级别 26)中推出,字间对齐为使用空格字符进行分段的语言(如中文、日文等)提供了类似的功能。

使用 JUSTIFICATION_MODE_NONE 的日文文本布局。
使用 JUSTIFICATION_MODE_NONE 的英文文本布局。


使用 JUSTIFICATION_MODE_INTER_WORD 的日文文本布局。
使用 JUSTIFICATION_MODE_INTER_WORD 的英文文本布局。


使用 JUSTIFICATION_MODE_INTER_CHARACTER 的日文文本布局。
使用 JUSTIFICATION_MODE_INTER_CHARACTER 的英文文本布局。

自动换行配置

Android 从 Android 13(API 级别 33)开始支持基于短语的日文和韩文换行。但是,虽然基于短语的换行可以提高短文本行的可读性,但它们并不适用于长文本行。在 Android 15 中,应用可以使用 LINE_BREAK_WORD_STYLE_AUTO 选项仅为短文本行应用基于短语的换行。此选项将为文本选择最佳的单词样式选项。

对于短文本行,使用基于短语的换行符,其功能与LINE_BREAK_WORD_STYLE_PHRASE相同,如下图所示

对于短文本行,LINE_BREAK_WORD_STYLE_AUTO应用基于短语的换行符以提高文本的可读性。这与应用LINE_BREAK_WORD_STYLE_PHRASE相同。

对于长文本行,LINE_BREAK_WORD_STYLE_AUTO使用无换行符样式,其功能与LINE_BREAK_WORD_STYLE_NONE相同,如下图所示

对于长文本行,LINE_BREAK_WORD_STYLE_AUTO应用无换行符样式以提高文本的可读性。这与应用LINE_BREAK_WORD_STYLE_NONE相同。

新增日文片假名字体

Android 15 默认捆绑了一个旧日文平假名(称为片假名)的字体文件。片假名字符独特的形状可以为艺术作品或设计增添独特的风格,同时也有助于准确地传递和理解古代日文文档。

日文片假名字体的字符和文本样式。

VideoLAN 圆锥体版权所有 (c) 1996-2010 VideoLAN。任何人都可以使用或修改此徽标或其修改版本来指代 VideoLAN 项目或 VideoLAN 团队开发的任何产品,但这并不表示该项目认可。

Vulkan 和 Vulkan 徽标是 Khronos Group Inc. 的注册商标。

OpenGL 是注册商标,OpenGL ES 徽标是 Hewlett Packard Enterprise 的商标,经 Khronos 许可使用。