API 级别:18
Android 4.3 (JELLY_BEAN_MR2
)
是对 Jelly Bean 版本的更新,为用户和应用提供了新功能
开发者。本文档介绍了
新 API。
作为应用开发者,您应下载 Android 4.3 系统映像 和 SDK 平台(位于 SDK 管理器中)作为 问题。如果您没有运行 Android 4.3 的设备 使用 Android 4.3 系统测试您的应用 映像,以在 Android 模拟器上测试您的应用。 然后,针对 Android 4.3 平台构建应用,以便开始使用 最新的 API。
更新目标 API 级别
为了更好地针对运行 Android 4.3 的设备优化您的应用,
您应将 targetSdkVersion
设置为
"18"
,将其安装在 Android 4.3 系统映像上;
然后发布包含此更改的更新
您可以在使用 Android 4.3 中的 API 的同时,通过添加
条件,在执行之前检查系统 API 级别
您的minSdkVersion
不支持的 API。
要详细了解如何保持向后兼容性,请阅读支持不同
平台版本。
Android 支持库中还提供了各种 API,允许您实现 旧版本平台上的新功能
如需详细了解 API 级别的工作原理,请参阅什么是 API 水平?
重要的行为变更
如果您之前发布过 Android 应用,请注意您的应用可能 会受到 Android 4.3 变更的影响。
如果您的应用使用隐式 intent...
您的应用在受限个人资料环境中可能会出现异常。
受限个人资料环境中的用户可能不会
提供所有可用的标准 Android 应用例如,受限个人资料可能具有
网络浏览器和相机应用已停用。因此,您的应用不应对哪些应用
因为如果您在调用 startActivity()
时未使用
验证应用是否能够处理 Intent
;
您的应用可能会在受限个人资料中崩溃。
使用隐式 intent 时,您应始终通过调用 resolveActivity()
或 queryIntentActivities()
来验证应用是否可以处理 intent。例如:
Kotlin
val intent = Intent(Intent.ACTION_SEND) ... if (intent.resolveActivity(packageManager) != null) { startActivity(intent) } else { Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show() }
Java
Intent intent = new Intent(Intent.ACTION_SEND); ... if (intent.resolveActivity(getPackageManager()) != null) { startActivity(intent); } else { Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show(); }
如果您的应用依赖于账号...
您的应用在受限个人资料环境中可能会出现异常。
默认情况下,受限个人资料环境中的用户无权访问用户账号。
如果您的应用依赖于 Account
,则应用可能会崩溃或行为
在受限个人资料中使用时会出现意外。
如果您想彻底阻止受限个人资料使用您的应用
应用依赖于敏感的账号信息,请在清单的 <application>
中指定 android:requiredAccountType
属性
元素。
如果您想允许受限个人资料(即使他们无法取得使用权限)继续使用您的应用 自己创建账号,那么您可以停用需要使用账号的应用功能 或允许受限个人资料访问主要用户创建的账号。有关 请参阅本节 支持受限个人资料中的账号。
如果您的应用使用 VideoView...
您的视频在 Android 4.3 设备上可能会变小。
在以前的 Android 版本中,VideoView
widget 错误地
计算出 layout_height
和 layout_width
的 "wrap_content"
值,使其与 "match_parent"
的值相同。因此,虽然之前使用 "wrap_content"
设置高度或宽度,但可能已经提供了您所需的视频布局,
否则,在 Android 4.3 及更高版本的设备上,视频可能会小得多。要解决此问题,请将
与"match_parent"
"wrap_content"
,并验证你的视频在
Android 4.3 及更低版本。
受限个人资料
在 Android 平板电脑上,用户现在可以根据主要用户创建受限个人资料。 用户创建受限个人资料后,可以启用限制,例如哪些应用 具体数据Android 4.3 中的一组新 API 还允许您构建 您开发的应用的限制设置。例如,通过使用新 API,您可以 当您的应用在移动应用中运行时, 受限个人资料环境
供用户控制您制定的限制的界面由系统的
“Settings”应用。若要向用户显示应用的限制设置,请执行以下操作:
您必须通过创建用于接收 ACTION_GET_RESTRICTION_ENTRIES
intent 的 BroadcastReceiver
来声明应用提供的限制。系统会调用此 intent 来查询
然后构建界面以允许主要用户执行以下操作:
为每个受限个人资料管理限制。
在以下内容的 onReceive()
方法中,
BroadcastReceiver
,则必须为应用提供的每个限制创建一个 RestrictionEntry
。每个 RestrictionEntry
都定义了限制标题、说明和
以下数据类型:
TYPE_BOOLEAN
表示限制 true 或 false。TYPE_CHOICE
表示限制 互斥的多个选项(单选按钮选项)。TYPE_MULTI_SELECT
表示 具有多个不互斥的选项(复选框选项)。
然后,将所有 RestrictionEntry
对象放入 ArrayList
中,并将其作为
EXTRA_RESTRICTIONS_LIST
extra。
系统在“设置”应用中为应用的限制创建界面,并保存每个界面
使用您为每个 RestrictionEntry
提供的唯一密钥进行限制
对象。当用户打开您的应用时,您可以通过以下方式查询任何当前限制:
正在调用 getApplicationRestrictions()
。
这将返回一个 Bundle
,其中包含每个限制的键值对
使用 RestrictionEntry
对象定义的事件。
如果要提供无法通过布尔值、单个
和多选值,那么您可以创建一个 Activity,在该 Activity 中,用户可以指定
并允许用户通过限制设置打开相应 activity。在
广播接收器,请添加 EXTRA_RESTRICTIONS_INTENT
extra
在结果 Bundle
中找到。此 extra 必须指定 Intent
指示要启动的 Activity
类(使用
putParcelable()
方法使用 intent 传递 EXTRA_RESTRICTIONS_INTENT
)。
当主要用户进入您的 activity 以设置自定义限制时,您的
然后,activity 必须使用
EXTRA_RESTRICTIONS_LIST
或 EXTRA_RESTRICTIONS_BUNDLE
键,具体取决于您是否指定
RestrictionEntry
对象或键值对。
支持受限个人资料中的账号
添加到主要用户的任何账号都可以用于受限个人资料,但
默认情况下,您无法通过 AccountManager
API 访问账号。
如果您在受限模式下尝试添加AccountManager
账号
则您会收到失败结果。由于存在这些限制,您有以下限制:
三个选项:
要从受限个人资料访问账号,您必须将 android:restrictedAccountType
属性添加到 <application> 标记中:
<application ... android:restrictedAccountType="com.example.account.type" >
注意:启用此属性后, 从受限个人资料访问主要用户账号的应用权限。因此,您应该允许 仅当应用显示的信息不会泄露个人身份信息时 个人身份信息 (PII) 的。主服务器 用户,您的应用会向其账号授予受限个人资料,因此应明确告知用户 账号访问权限对于应用的功能非常重要。如果可能的话,您还应该 为主要用户提供足够的限制控制功能,从而确定对账号的访问权限 。
如果您想使用账号,但实际上并不需要为应用的主要功能提供账号
,您可以检查账号是否可用,并在不可用时停用某些功能。
您应首先检查是否有可用的现有账号。如果没有,则查询
您可以通过调用 getUserRestrictions()
来创建新账号,并在结果中查看 DISALLOW_MODIFY_ACCOUNTS
extra。如果值为 true
,
则您应停用应用中需要访问账号的所有功能。
例如:
Kotlin
val um = context.getSystemService(Context.USER_SERVICE) as UserManager val restrictions: Bundle = um.userRestrictions if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { // cannot add accounts, disable some functionality }
Java
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); Bundle restrictions = um.getUserRestrictions(); if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { // cannot add accounts, disable some functionality }
注意:在这种情况下,您不需要声明 任何新属性。
您的应用不可提供给受限个人资料使用,因为这是出于以下原因:
应用依赖于账号中的敏感个人信息(以及受限个人资料
目前无法添加新账号),请添加
将 android:requiredAccountType
属性添加到 <application> 标记:
<application ... android:requiredAccountType="com.example.account.type" >
例如,Gmail 应用使用此属性为受限个人资料、 因为受限个人资料无法访问所有者的个人电子邮件地址。
无线和连接
蓝牙低功耗(智能支持)
Android 现通过 android.bluetooth
中的新 API 支持低功耗蓝牙 (LE)。
借助这些新 API,您可以构建能够与低功耗蓝牙通信的 Android 应用
心率监测仪和计步器等外围设备。
因为蓝牙 LE 是一项硬件功能,并非所有
则您必须在清单文件中声明 <uses-feature>
"android.hardware.bluetooth_le"
的元素:
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
如果您已熟悉 Android 的传统蓝牙 API,请注意使用
Bluetooth LE API 有一些差异。最重要的是,现在您应该将 BluetoothManager
类用于一些高级操作
例如获取 BluetoothAdapter
、获取已连接
以及检查设备状态。例如,现在您应通过以下方式获取
BluetoothAdapter
:
Kotlin
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager bluetoothAdapter = bluetoothManager.adapter
Java
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); bluetoothAdapter = bluetoothManager.getAdapter();
如需发现蓝牙 LE 外围设备,请对 BluetoothAdapter
调用 startLeScan()
,并向其传递实现
BluetoothAdapter.LeScanCallback
接口的实现。当蓝牙
适配器检测到蓝牙 LE 外围设备时,您的 BluetoothAdapter.LeScanCallback
实现会收到对
onLeScan()
方法。这个
方法会为您提供一个 BluetoothDevice
对象,该对象表示
检测到的设备、设备的 RSSI 值以及包含设备
广告记录。
如果您只想扫描特定类型的外围设备,则可以改为调用 startLeScan()
并加入 UUID
对象数组,以指定应用支持的 GATT 服务。
注意:您只能扫描蓝牙 LE 设备或 使用之前的 API 扫描传统蓝牙设备。您不能同时扫描 LE 和传统 LE 同时支持蓝牙设备。
然后,如需连接到蓝牙 LE 外围设备,请在相应设备上调用 connectGatt()
BluetoothDevice
对象,向其传递一个实现
BluetoothGattCallback
。您的 BluetoothGattCallback
实现会收到有关连接的回调
设备状态和其他事件。现在是onConnectionStateChange()
回调,当该方法将 STATE_CONNECTED
作为新状态传递时,您可以开始与设备通信。
如要在设备上访问蓝牙功能,您的应用还必须请求特定 蓝牙用户权限。如需更多信息,请参阅蓝牙低功耗 API 指南。
WLAN 仅扫描模式
在尝试识别用户的位置时,Android 可能会使用 Wi-Fi 来帮助确定 通过扫描附近的接入点确定位置信息。不过,用户通常会关闭 Wi-Fi, 节约电量,导致位置数据不太准确。Android 现在包含一个 仅扫描模式,允许设备 Wi-Fi 扫描接入点以帮助获取位置信息 从而大大减少电池用量。
如果您希望获取用户的位置,但 Wi-Fi 当前处于关闭状态,您可以请求
用户可通过使用 ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE
操作调用 startActivity()
以启用 Wi-Fi 仅扫描模式。
Wi-Fi 配置
借助新的 WifiEnterpriseConfig
API,面向企业的服务
为受管设备自动配置 Wi-Fi。
快速回复来电
从 Android 4.0 开始,我们推出了一项名为“快速回复”的功能,使用户可以对传入的
通过即时短信进行通话,而无需接听来电或解锁设备。
在此之前,这些快速消息始终由默认“短信”应用处理。现在,任何应用
可以通过创建一个 Service
来声明处理这些消息的能力
,并使用针对 ACTION_RESPOND_VIA_MESSAGE
的 intent 过滤器。
当用户使用快速回复来响应来电时,“电话”应用会发送
包含 URI 的 ACTION_RESPOND_VIA_MESSAGE
intent
用于描述接收方(调用方)和 EXTRA_TEXT
extra
替换为用户想要发送的消息。当您的服务收到 intent 时,它应该会传递
消息并立即停止自身运行(您的应用不应显示 activity)。
为了接收此 intent,您必须声明 SEND_RESPOND_VIA_MESSAGE
权限。
多媒体
MediaExtractor 和 MediaCodec 增强功能
Android 现在可让您更轻松地编写自己的动态自适应
符合 ISO/IEC 23009-1 标准的 HTTP (DASH) 播放器流式传输
使用 MediaCodec
和 MediaExtractor
中的现有 API。这些 API 的底层框架已更新,可支持
解析碎片化的 MP4 文件,但您的应用仍负责解析 MPD 元数据
并将各个流传递给 MediaExtractor
。
如果要将 DASH 用于加密内容,请注意 getSampleCryptoInfo()
方法会返回描述每个加密媒体结构的 MediaCodec.CryptoInfo
元数据
示例。此外,getPsshInfo()
方法已添加到
MediaExtractor
,以便您可以访问 DASH 媒体的 PSSH 元数据。
此方法会返回 UUID
对象到字节的映射,其中
UUID
,用于指定加密方案,字节是数据专属
架构。
媒体数字版权管理
新的 MediaDrm
类提供模块化的数字版权解决方案
管理 (DRM) 来实现媒体内容的管理,以便将 DRM 问题与媒体播放分开。对于
例如,这种 API 分离可让您播放 Widevine 加密内容,而无需
以便使用 Widevine 媒体格式。此 DRM 解决方案还支持 DASH 通用加密,因此您可以
可以对您的流媒体内容使用各种数字版权管理方案。
您可以使用 MediaDrm
获取不透明的键请求消息并处理
从服务器发送密钥响应消息,以获取和配置许可。您的应用
负责处理与服务器的网络通信;MediaDrm
类仅提供生成和处理消息的功能。
MediaDrm
API 旨在与
Android 4.1(API 级别 16)中引入的 MediaCodec
API;
包括 MediaCodec
(用于处理内容编码和解码)、MediaCrypto
(用于处理加密的内容)和 MediaExtractor
用于提取内容以及对内容进行多路复用。
您必须先构建 MediaExtractor
并
MediaCodec
对象。然后,您就可以访问
UUID
,通常来自内容中的元数据,并使用它来构建
MediaDrm
对象的实例及其构造函数。
通过 Surface 进行视频编码
Android 4.1(API 级别 16)为低层级 API 添加了 MediaCodec
类
媒体内容的编码和解码。对视频进行编码时,Android 4.1 要求您
带有 ByteBuffer
数组的媒体,但 Android 4.3 现在允许您使用 Surface
作为编码器的输入。例如,你可以将输入
或从现有视频文件导入,也可以使用从 OpenGL ES 生成的帧。
如需使用 Surface
作为编码器的输入,请先为 MediaCodec
调用 configure()
。
然后,调用 createInputSurface()
以接收 Surface
,然后您就可以在其上流式传输媒体内容。
例如,您可以将给定的 Surface
用作 OpenGL 的窗口
传递给 eglCreateWindowSurface()
。然后,在渲染 Surface 时,调用 eglSwapBuffers()
以将帧传递给 MediaCodec
。
如需开始编码,请对 MediaCodec
调用 start()
。完成后,调用 signalEndOfInputStream()
终止编码,并对release()
Surface
。
媒体多路复用
新的 MediaMuxer
类支持在一个音频流之间实现多路复用
一个视频流这些 API 是 MediaExtractor
的对应项
Android 4.2 中添加了用于对媒体进行去复用(多路复用)媒体的类。
MediaMuxer.OutputFormat
中定义了支持的输出格式。目前,
MP4 是唯一受支持的输出格式,MediaMuxer
目前支持
一次只能有一个音频流和/或一个视频串流。
MediaMuxer
主要与 MediaCodec
配合使用
因此您可以通过 MediaCodec
执行视频处理,然后保存
通过 MediaMuxer
将内容输出为 MP4 文件。您还可以将 MediaMuxer
与 MediaExtractor
结合使用,以执行
媒体编辑功能,而无需编码或解码。
RemoteControlClient 的播放进度和调试
在 Android 4.0(API 级别 14)中,RemoteControlClient
已添加到
从远程控制客户端启用媒体播放控件,例如
锁定屏幕。Android 4.3 现在可让此类控制器显示播放内容
位置和用于拖动播放的控件。如果您已经为自己的
媒体应用与 RemoteControlClient
API 相关联,那么您可以允许播放
通过实现两个新接口来轻松擦除数据
首先,您必须启用 FLAG_KEY_MEDIA_POSITION_UPDATE
标志,方法是将该标志传递给
setTransportControlsFlags()
。
然后,实现以下两个新接口:
RemoteControlClient.OnGetPlaybackPositionListener
- 这包括用于请求当前位置的
onGetPlaybackPosition()
回调 。 RemoteControlClient.OnPlaybackPositionUpdateListener
- 其中包括
onPlaybackPositionUpdate()
回调, 当用户使用 遥控器界面。使用新位置更新播放内容时,请调用
setPlaybackState()
以指示 新的播放状态、位置和速度
定义这些接口后,您可以通过调用 setOnGetPlaybackPositionListener()
为 RemoteControlClient
设置这些接口,
setPlaybackPositionUpdateListener()
。
图形
对 OpenGL ES 3.0 的支持
Android 4.3 添加了 Java 接口和对 OpenGL ES 3.0 的原生支持。主要的新功能 包括:
- 加速高级视觉效果
- 将高质量 ETC2/EAC 纹理压缩作为标准功能
- 新版 GLSL ES 着色语言,支持整数和 32 位浮点
- 高级纹理渲染
- 对纹理大小和渲染缓冲区格式进行更广泛的标准化
Android 上 OpenGL ES 3.0 的 Java 接口随 GLES30
一起提供。
使用 OpenGL ES 3.0 时,务必使用
<uses-feature>
标记和 android:glEsVersion
属性。例如:
<manifest> <uses-feature android:glEsVersion="0x00030000" /> ... </manifest>
请务必通过调用 setEGLContextClientVersion()
来指定 OpenGL ES 上下文,
传递 3
作为版本。
有关使用 OpenGL ES 的详细信息,包括如何检查设备是否支持 在运行时使用 OpenGL ES 版本,请参阅 OpenGL ES API 指南。
针对可绘制对象的 Mipmapping
使用 mipmap 作为位图或可绘制对象的源是一种提供 以及各种不同的比例尺度,这对于 在动画播放过程中缩放的图片。
Android 4.2(API 级别 17)在 Bitmap
中添加了对 mipmap 的支持
类 - 完成上述操作后,Android 会交换 Bitmap
中的 mip 图片。
提供了 mipmap 源代码并启用了 setHasMipMap()
。现在,在 Android 4.3 中,您还可以为 BitmapDrawable
对象启用 mipmap,方法是提供 mipmap 资源和
在位图资源文件中设置 android:mipMap
属性,或通过调用 hasMipMap()
进行设置。
界面
查看叠加层
新的 ViewOverlay
类在顶部提供一个透明层
一个 View
,您可以在其中添加视觉内容,并且不会影响
布局层次结构您可以通过调用 getOverlay()
获取任何 View
的 ViewOverlay
。叠加层
始终与其主视图(创建它的视图)具有相同的大小和位置,
这样你就可以添加显示在主视图前,但不能扩展内容
托管视图的边界
在创建映像时,使用 ViewOverlay
特别有用
提供动画效果,例如将视图滑出容器或在屏幕上移动项目
而不会影响视图层次结构不过,由于叠加层的可用区域是
(如果您要为向外移动的视图添加动画效果)
则必须使用父视图中的叠加层,该叠加层具有所需
布局边界。
为 widget 视图(如 Button
)创建叠加层时,您需要
可通过调用 Drawable
对象向叠加层添加
add(Drawable)
。如果针对布局视图(例如 RelativeLayout
)调用 getOverlay()
,
返回的对象是 ViewGroupOverlay
。通过
ViewGroupOverlay
类是一个子类
(总共 ViewOverlay
),您还可以添加View
调用 add(View)
来传递对象。
注意:您添加到叠加层中的所有可绘制对象和视图 都只能是可见的它们无法接收焦点事件或输入事件。
例如,以下代码通过将视图放置到右边以动画方式显示视图。 ,然后在该视图上执行平移动画:
Kotlin
val view: View? = findViewById(R.id.view_to_remove) val container: ViewGroup? = view?.parent as ViewGroup container?.apply { overlay.add(view) ObjectAnimator.ofFloat(view, "translationX", right.toFloat()) .start() }
Java
View view = findViewById(R.id.view_to_remove); ViewGroup container = (ViewGroup) view.getParent(); container.getOverlay().add(view); ObjectAnimator anim = ObjectAnimator.ofFloat(view, "translationX", container.getRight()); anim.start();
光学边界布局
对于包含九宫格背景图片的视图,您现在可以指定它们 与相邻视图对齐的您可以输入背景图片的边界 而不是“剪辑”视图边界。
例如,图 1 和图 2 显示的布局相同,但图 1 中的版本为 使用裁剪边界(默认行为),而图 2 则使用光学边界。由于 用于按钮和相框的九宫格图像边缘有内边距, 在使用裁剪边界时,这些标签与文本或文本之间不会显示。
注意:图 1 和图 2 中的屏幕截图包含 布局边界"已启用开发者设置。对于每个视图,红线表示 边界,蓝线表示裁剪边界,粉色表示外边距。
如需根据视图的光学边界对齐视图,请在其中一个父布局中将 android:layoutMode
属性设置为 "opticalBounds"
。例如:
<LinearLayout android:layoutMode="opticalBounds" ... >
为此,应用于视图背景的九宫格图像必须指定 9-patch 文件底部和右侧的红色线条表示光学边界(如 如图 3 所示)。红线表示需要减去的区域 裁剪边界,保留图片的光学边界。
在布局中为 ViewGroup
启用光学边界后,所有
后代视图会继承光学边界布局模式,除非您为分组依据替换该模式
将 android:layoutMode
设置为 "clipBounds"
。所有布局元素也都遵循
子视图的光学边界,根据
以及其中的视图不过,布局元素(ViewGroup
的子类)
目前不支持应用于自身背景的九宫格图像的光学边界。
如果您通过创建 View
、ViewGroup
或其任何子类的子类来创建自定义视图,则您的视图将继承这些光学绑定行为。
注意:Holo 主题支持的所有微件都已更新
具有光学边界,包括 Button
、Spinner
、
EditText
,等等。因此,您可以设置
将 android:layoutMode
属性设为 "opticalBounds"
(如果您的应用应用了 Holo 主题)
(Theme.Holo
、Theme.Holo.Light
等)。
如要使用 Draw 9-patch 工具为您自己的九宫格图像指定光学边界,请在出现以下情况时按住 Ctrl 键: 点击边框像素即可
Rect 值的动画
您现在可以使用新的 RectEvaluator
在两个 Rect
值之间添加动画效果。这个新类是 TypeEvaluator
的实现,您可以将其传递给 ValueAnimator.setEvaluator()
。
窗口附加和焦点监听器
以前,如果您想监听视图何时附加/分离到窗口,或者
您需要替换 View
类,
分别实现 onAttachedToWindow()
和 onDetachedFromWindow()
或 onWindowFocusChanged()
。
现在,如需接收附加和分离事件,您可以改为实现 ViewTreeObserver.OnWindowAttachListener
,并使用以下代码在视图上设置它
addOnWindowAttachListener()
。
如需接收焦点事件,您可以实现 ViewTreeObserver.OnWindowFocusChangeListener
,并使用以下代码在视图上设置它
addOnWindowFocusChangeListener()
。
电视过扫描支持
为确保应用填满每台电视的整个屏幕,您现在可以启用过扫描
应用布局过扫描模式由 FLAG_LAYOUT_IN_OVERSCAN
标志决定,您可以使用如下平台主题启用该标志:
Theme_DeviceDefault_NoActionBar_Overscan
或启用
自定义主题中的 windowOverscan
样式。
屏幕方向
<activity>
代码的 screenOrientation
属性现在支持其他值,以遵从用户的自动屏幕旋转偏好:
"userLandscape"
- 行为与
"sensorLandscape"
相同,除非用户停用了自动屏幕旋转功能 则会在正常的横向方向上锁定,而不会翻转。 "userPortrait"
- 行为与
"sensorPortrait"
相同,除非用户随后停用了自动屏幕旋转功能 它就会锁定在正常的纵向方向,而不会翻转。 "fullUser"
- 行为与
"fullSensor"
相同,并且允许向所有四个方向旋转,但以下四个方向除外: 如果用户停用自动屏幕旋转,屏幕将锁定在用户首选方向上。
此外,您现在还可以声明 "locked"
以将应用的屏幕方向锁定为
屏幕的当前方向。
旋转动画
新 rotationAnimation
字段
WindowManager
可让您从自己设置的三种动画中选择其一
。三个动画是:
注意:仅当您将 activity 设置为使用“全屏”时,这些动画才可用模式,您可以使用 Theme.Holo.NoActionBar.Fullscreen
等主题启用该模式。
例如,下面展示了如何启用“淡入淡出”动画:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val params: WindowManager.LayoutParams = window.attributes params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE window.attributes = params ... }
Java
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); WindowManager.LayoutParams params = getWindow().getAttributes(); params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE; getWindow().setAttributes(params); ... }
用户输入
新传感器类型
借助新的 TYPE_GAME_ROTATION_VECTOR
传感器,您可以检测设备的旋转情况,而无需担心磁场干扰。与 TYPE_ROTATION_VECTOR
传感器不同,TYPE_GAME_ROTATION_VECTOR
并非基于磁北。
新的 TYPE_GYROSCOPE_UNCALIBRATED
和 TYPE_MAGNETIC_FIELD_UNCALIBRATED
传感器可提供原始传感器数据,而无需
考虑到偏差估算的因素。也就是说,现有的 TYPE_GYROSCOPE
和 TYPE_MAGNETIC_FIELD
传感器提供的传感器数据考虑到了由陀螺仪漂移和硬铁产生的估算偏差
。而新的“未校准”则这些传感器的版本
原始传感器数据并单独提供估算的偏差值。借助这些传感器,您可以
通过使用
外部数据
通知监听器
Android 4.3 添加了新的服务类 NotificationListenerService
,可让您的应用在系统发布新通知时接收有关这些通知的信息。
如果您的应用目前使用无障碍服务 API 访问系统通知,您应更新应用以改用这些 API。
联系人提供程序
查询“contactables”
新的联系人提供程序查询 Contactables.CONTENT_URI
提供了一种有效的方法,用于获取一个 Cursor
,其中包含属于与指定查询匹配的所有联系人的所有电子邮件地址和电话号码。
查询联系人增量
联系人提供程序中新增了一些 API,可让您高效地查询联系人数据的近期更改。以前,当联系人数据中的某些内容发生更改时,您的应用会收到通知,但您并不了解具体更改内容,并且需要检索所有联系人,然后进行迭代以发现更改。
如需跟踪对插入内容和更新的更改,您现在可以在选择中包含 CONTACT_LAST_UPDATED_TIMESTAMP
参数,以仅查询自上次查询提供程序以来更改的联系人。
为了跟踪哪些联系人已被删除,新表 ContactsContract.DeletedContacts
会提供已删除的联系人日志(但每个已删除的联系人都会在此表中保留一段时间)。与 CONTACT_LAST_UPDATED_TIMESTAMP
类似,您可以使用新的选择参数 CONTACT_DELETED_TIMESTAMP
来检查自上次查询提供程序以来哪些联系人已被删除。该表还包含 DAYS_KEPT_MILLISECONDS
常量,该常量包含日志将保留的天数(以毫秒为单位)。
此外,当用户遇到以下情况时,联系人提供程序现在会广播 CONTACTS_DATABASE_CREATED
操作
通过系统设置菜单清除联系人存储空间,从而有效地重新创建
联系人提供程序数据库。它旨在向应用发出信号,指示它们需要断开所有联系
并使用新的查询重新加载该数据。
有关使用这些 API 检查联系人更改的示例代码,请在 ApiDemos 中查找 SDK 示例下载中提供了示例。
本地化
改进了对双向文本的支持
旧版 Android 支持从右到左 (RTL) 的语言和布局,
但有时无法正确处理混合方向文本。因此,Android 4.3 添加了 BidiFormatter
API,可帮助您正确设置反向文本格式
而不会对内容的任何部分进行乱码
例如,当要创建一个带有字符串变量的句子时,比如“您是不是要找
15 Bay Street, Laurel, CA?”的指令,则通常会将已本地化的字符串资源和变量传递给
String.format()
:
Kotlin
val suggestion = String.format(resources.getString(R.string.did_you_mean), address)
Java
Resources res = getResources(); String suggestion = String.format(res.getString(R.string.did_you_mean), address);
但是,如果语言区域是希伯来语,则格式化的字符串将如下所示:
האם התכוונת ל 15 Bay Street, Laurel, CA?
这是错误的,因为“15”应该放在“Bay Street”的左边。解决方案是使用 BidiFormatter
及其 unicodeWrap()
方法。例如,上面的代码变为:
Kotlin
val bidiFormatter = BidiFormatter.getInstance() val suggestion = String.format( resources.getString(R.string.did_you_mean), bidiFormatter.unicodeWrap(address) )
Java
Resources res = getResources(); BidiFormatter bidiFormatter = BidiFormatter.getInstance(); String suggestion = String.format(res.getString(R.string.did_you_mean), bidiFormatter.unicodeWrap(address));
默认情况下,unicodeWrap()
会使用
第一强方向性估计启发式算法,如果第一个是
指示文本方向的信号并未表示整体内容的合适方向。
如有必要,您可以通过传递 TextDirectionHeuristics
中的某个 TextDirectionHeuristic
常量来指定其他启发法
发送至 unicodeWrap()
。
注意:这些新 API 也可用于以前的版本
通过 Android支持
库,其中包含 BidiFormatter
类和相关 API。
无障碍服务
处理按键事件
AccessibilityService
现在可以接收
使用 onKeyEvent()
回调方法实现按键输入事件。这样,您的无障碍服务就可以处理
基于按键的输入设备(如键盘)并将这些事件转换为
以前可能只能通过触摸输入或设备的方向键实现。
选择文本并复制/粘贴
AccessibilityNodeInfo
现在提供的 API
一个用于选择、剪切、复制和粘贴的 AccessibilityService
文本。
要指定要剪切或复制的文字,您的无障碍服务可以使用新的
操作,ACTION_SET_SELECTION
,正在传递
为其选择起始位置和结束位置,位置为 ACTION_ARGUMENT_SELECTION_START_INT
和 ACTION_ARGUMENT_SELECTION_END_INT
。
您也可以使用现有的
操作,ACTION_NEXT_AT_MOVEMENT_GRANULARITY
(之前仅用于移动光标位置),并添加参数 ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
。
您可以使用 ACTION_CUT
进行剪切或复制,
ACTION_COPY
,随后使用
ACTION_PASTE
。
注意:这些新 API 也可用于以前的版本
通过 Android支持
包含 AccessibilityNodeInfoCompat
的库
类。
声明无障碍功能
从 Android 4.3 开始,无障碍服务必须声明无障碍功能
,才能使用某些无障碍功能。如果该功能
则此地图项将为空操作。要声明服务的
因此您必须使用与各种
“功能”AccessibilityServiceInfo
中的常量
类。
例如,如果某项服务未请求 flagRequestFilterKeyEvents
功能,
那么它收不到按键事件
测试和调试
自动化界面测试
新的 UiAutomation
类提供了可让您模拟用户的 API,
用于测试自动化的操作。通过使用平台的 AccessibilityService
API,UiAutomation
通过 API,您可以检查屏幕内容并注入任意键盘和触摸事件。
如需获取 UiAutomation
的实例,请调用 Instrumentation.getUiAutomation()
。订单
为使此操作生效,您必须在 instrument
命令中提供 -w
选项
从 adb shell
运行 InstrumentationTestCase
时。
借助 UiAutomation
实例,您可以执行任意事件来测试
您的应用,方法是调用 executeAndWaitForEvent()
,并向其传递要执行的 Runnable
(超时)
操作的时间段以及 UiAutomation.AccessibilityEventFilter
接口的实现。您会在 UiAutomation.AccessibilityEventFilter
实现中收到来电
让您可以过滤出感兴趣的事件,
测试失败
如需在测试期间观察所有事件,请创建 UiAutomation.OnAccessibilityEventListener
的实现并将其传递给 setOnAccessibilityEventListener()
。
然后,您的监听器接口会收到对 onAccessibilityEvent()
的调用
每次事件发生时接收 AccessibilityEvent
对象
来描述该事件
UiAutomation
API 还提供各种其他操作
以鼓励开发 uiautomator 等界面测试工具。例如,
UiAutomation
还可以:
- 注入输入事件
- 更改屏幕的方向
- 截取屏幕截图
最重要的是,对于界面测试工具,UiAutomation
API 可以
这与 Instrumentation
中的不同。
适用于应用的 Systrace 事件
Android 4.3 添加了 Trace
类,其中包含两个静态方法,
beginSection()
和endSection()
:
允许您定义要包含在 Systrace 报告中的代码块。通过创建
可跟踪代码段,systrace 日志会向您提供更详细的
并分析应用中发生运行速度缓慢的环节
如需了解如何使用 Systrace 工具,请参阅使用 Systrace 分析展示广告和性能。
安全
适用于应用私钥的 Android 密钥库
Android 现在在 KeyStore
中提供自定义 Java 安全提供程序
名为“Android 密钥库”的工具
可能只有您的应用可以查看和使用。要加载 Android 密钥库,请将
将"AndroidKeyStore"
更改为KeyStore.getInstance()
。
如需管理您的应用在 Android 密钥库中的私有凭据,请使用以下代码生成新密钥:
KeyPairGeneratorSpec
会员价为 KeyPairGenerator
。第一页
通过调用 getInstance()
获取 KeyPairGenerator
的实例。然后调用
initialize()
,向其传递
KeyPairGeneratorSpec
,您可以使用
KeyPairGeneratorSpec.Builder
。
最后,通过调用 generateKeyPair()
获取 KeyPair
。
硬件凭据存储
Android 现在支持为您的 KeyChain
提供由硬件支持的存储空间
凭据,通过使密钥无法提取来提高安全性。也就是说,
密钥位于由硬件支持的密钥库(安全元件、TPM 或 TrustZone)中,因此可用于
加密操作,但无法导出私钥材料。甚至操作系统内核
无法访问此密钥材料。虽然并非所有 Android 设备都支持
则可通过调用
KeyChain.IsBoundKeyAlgorithm()
。
清单声明
可声明的必备功能
<uses-feature>
现在支持以下值
元素,这样可以确保您的应用仅安装在提供相应功能的设备上
应用需求
FEATURE_APP_WIDGETS
- 声明您的应用提供应用微件,并且应仅安装在符合以下条件的设备上
提供可供用户嵌入应用微件的主屏幕或类似位置。
示例:
<uses-feature android:name="android.software.app_widgets" android:required="true" />
FEATURE_HOME_SCREEN
- 声明您的应用充当主屏幕替换项,仅应安装在
支持第三方主屏幕应用的设备。
示例:
<uses-feature android:name="android.software.home_screen" android:required="true" />
FEATURE_INPUT_METHODS
- 声明您的应用提供自定义输入法(使用
InputMethodService
构建的键盘),并且应仅安装在符合以下条件的设备上: 支持第三方输入法。 示例:<uses-feature android:name="android.software.input_methods" android:required="true" />
FEATURE_BLUETOOTH_LE
- 声明您的应用使用蓝牙低功耗 API,并且应仅安装在设备上
能够通过低功耗蓝牙与其他设备进行通信。
示例:
<uses-feature android:name="android.software.bluetooth_le" android:required="true" />
用户权限
<uses-permission>
现在支持以下值
来声明
访问特定 API 所需的权限。
BIND_NOTIFICATION_LISTENER_SERVICE
- 必须使用新的
NotificationListenerService
API。 SEND_RESPOND_VIA_MESSAGE
- 接收
ACTION_RESPOND_VIA_MESSAGE
的必要条件 intent。
如需详细了解 Android 4.3 中的所有 API 变更,请参阅 API 差异报告。