作者:贺国睿、朱忠凯 腾讯移动客户端开发 高级工程师
商业转载请联系腾讯 WeTest 获得授权,非商业转载请注明出处。
原文链接:http://wetest.qq.com/lab/view/376.html

2018年3月8日,Google 推出了 Android P Preview 版本,并提供官方镜像下载。

为了让广大开发者能够及时了解 Android P 的新功能特性,提前为您的 app 进行良好适配,WeTest 决定限时免费开放 Android P Preview 版本的远程调试及标准兼容功能,供开发者进行体验。

即日起,针对 WeTest 平台的 Android P、Android Oreo 专区,个人认证用户可免费获得 30 分钟/天远程调试、3 次/天标准兼容测试额度;企业账户可获得 60 分钟/天远程调试、6 次/天标准兼容测试额度。


此外,WeTest 的技术专家就本次 Android P 的新特性,进行了一些简单的开发体验,供大家参考:

新功能特性抢先看

Android P 的新功能特性集中在了 UI、通知体验、室内定位、图像存储几个方面,解决了之前一直存在的痛点。例如 WiFi RTT 一定程度上弥补了蜂窝网络在室内环境下的定位问题,HEIC 图像格式则重点解决了存储容量问题。同时,Android P 也在通知丰富度及操作便捷性等功能方面有所增强和提升。

一、WiFi RTT 功能——复杂地形精确导航

WiFi RTT 功能是 Android P 新引入的一个功能,从原理上来说与蜂窝网络的定位原理一致,但这个功能极大的弥补了蜂窝网络在室内定位的短板,WiFi RTT 将能够在室内提供高精度的定位,这是蜂窝网络很难做到的。

WiFi RTT 是全新的功能,在 android.net.wifi 包下增加了 rtt 包,用于存放 WiFi RTT 相关类和接口。

WiFi RTT 的 API 以 WifiRttManager 为核心,借助 AP 热点或 WiFi,利用 RTT 原理完成测距,通过三个以上的测距点就能够准确地定位到设备所在位置。

WiFiRTTManager 提供了测距接口,是一个异步测距操作,根据 官方文档(https://developer.android.com/reference/android/net/wifi/rtt/WifiRttManager.html)说明,其测距接口如下:

void startRanging(RangingRequest request, RangingResultCallback callback, Handler handler);

注: SDK Platforms Android P Preview Revision 1 的相关接口定义与此不同,但实际的官方镜像中接口与此一致,开发者需要更新最新的 Android P Preview Revision 2,此版本中 Google 已经修正该接口。

接口中,RangingRequest 通过 RangingRequest.Builder 构建,RangingRequest.Builder 构建出 RangingRequest 所需要的参数可以通过 WiFiManager 等系统服务获取到相关的内容,如 List scanResults = wifiManager.getScanResults();

以下提供一个简单的测试 Demo,以供参考:

private WifiRttManager wifiRttManager;
private WifiManager wifiManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
// ... ...

if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)) {
Object service = this.getApplicationContext().getSystemService(Context.WIFI_RTT_RANGING_SERVICE);
if(service instanceof WifiRttManager) {
wifiRttManager= (WifiRttManager) service;
Log.i(TAG, "Get WifiRttManager Succ.");
}

wifiManager = (WifiManager) this.getApplicationContext().getSystemService(Context.WIFI_SERVICE);

IntentFilter wifiFileter = new IntentFilter();
wifiFileter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
wifiFileter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
wifiFileter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
registerReceiver(new WifiChangeReceiver(), wifiFileter);
}

// ... ...

private void startScanAPs() {
wifiManager.setWifiEnabled(true);
wifiManager.startScan();
}

class WifiChangeReceiver extends BroadcastReceiver {
@RequiresApi(api = 28)
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
List scanResults = wifiManager.getScanResults();
Log.i(TAG, "Wifi Scan size:" + scanResults.size());
for(ScanResult scanResult: scanResults) {
Log.i(TAG, scanResult.toString());
RangingRequest.Builder builder = new RangingRequest.Builder();
builder.addAccessPoint(scanResult);
wifiRttManager.startRanging(builder.build(), new RangingResultCallback() {
@SuppressLint("Override")
@Override
public void onRangingFailure(int i) {
// TODO
}
@SuppressLint("Override")
@Override
public void onRangingResults(List list) {
// TODO get result from list

for(RangingResult result : list) {
Log.i(TAG, result.toString());
}
}
}, new Handler());
}
}
}
}

使用 WiFi RTT 时,需要在 AndroidManifest.xml 中增加如下声明:

通过上面的简单代码,就能够实现 WiFi RTT 的功能。

WiFi RTT 功能适用于复杂地形的大型室内外场所,如商场、娱乐场所、大型休闲、游乐场等等,提供场所内的局部区域精确化导航等功能。相信在很快的时间内,就能够在各大地图应用内体验到这项便利功能,对于路痴、地图盲的伙伴们将是极大的福音。

二、显示剪切——支持刘海屏

随着 iPhone X 的推出,“刘海屏” 达到了空前的高潮。Android P 里提供了对异形屏幕的 UI 适配兼容方案,通过 DisplayCutout 类提供的相关接口,能够获取到屏幕中 Cutout 区域的信息。

借助 DisplayCutout,可以获取到如下信息:

DisplayCutout displayCutout = view.getRootWindowInsets().getDisplayCutout();
if(displayCutout != null) {
Region bounds = displayCutout.getBounds();
Log.d(TAG, String.format("Bounds:%s", bounds.toString()));
int top = displayCutout.getSafeInsetTop();
int bottom = displayCutout.getSafeInsetBottom();
int left = displayCutout.getSafeInsetLeft();
int right = displayCutout.getSafeInsetRight();
Log.d(TAG, String.format("Cutout edge:[left:%d, top:%d,right:%d, bottom:%d]", left, top, right, bottom));
}

public Region getBounds() 能够获取到 Cutout 区域的所有信息,Region 就是 Cutout 区域。

public int getSafeInsetTop()
public int getSafeInsetBottom()
public int getSafeInsetLeft()
public int getSafeInsetRight()

以上四个接口,可以获取到去除 Cutout 区域后的安全区域边界值。

通过上述数据,开发者能够精准的控制 UI 的绘制,避免将 UI 内容绘制到 Cutout 区域造成 UI 显示异常。

Android 机器里,刘海屏目前还是极为罕见的 Google 为了方便开发者调试,在 Android P Preview 镜像中,特别提供了 Cutout 的支持,具体打开方式可以参考 Google 提供的特性说明文档 cutout 小节内容。

如图所示,笔者使用手头的 Pixel 2 XL 体验了 Android P 的 Cutout 设置。

三、通知优化——操作更多样,内容更丰富

Android P 在通知内容的丰富度和操作上做了优化。

最近的版本中,Android 系统的通知管理方面一直优化升级,Android O 提供了更细粒度的 Channel 功能,通知栏推送时需要指定 NotificationChannel,用户可以对通知的 Channel 选择,只允许感兴趣的 Channel 推送的通知显示。通过通道设置、免打扰优化等方式,极大增强了消息体验。

增强消息体验

Android P 继续改进和增强消息通知 [v1] 。早在 Android 7.0 时,就提供了在通知中直接应答和输入,Android P 对这一功能做了更多的增强。

Android P 的通知中支持图像内容,可以通过 setData() 方法,给出消息的图像内容,在通知上展示給用户。

Android P 同样简化了通知的配置形式。Android P 中增加了 Notification.Person 类,用于区分同一个对话的参与者信息,如参与者的头像、URI 等。根据官方说明,Android P 中,通知消息的其他一些 API,也使用 Person 替代之前的 CharSequence。

简单的体验下新的 API 的开发:

NotificationChannel channel = new NotificationChannel("WtTestChannel",
"WtTestChannel", NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(true); // luncher icon right corner's point
channel.setLightColor(Color.RED); // read point
channel.setShowBadge(true); // whether show this channel notification on long press icon

Notification.Builder builder =
new Notification.Builder(MainActivity.this,
"WtTestChannel");
Notification.Person p = new Notification.Person();
p.setName("WeTest");
p.setUri("http://cdn.wetest.qq.com/" +
"ui/1.2.0/pc/static/image/newLogo-16042.png");
Notification.MessagingStyle messageStyle = new Notification.MessagingStyle(p);
Notification.MessagingStyle.Message message =
new Notification.MessagingStyle.Message("WeTestMessage", 2000, p);

//show image
Uri image = Uri.parse(
"http://cdn.wetest.qq.com/ui/1.2.0/pc/static/image/newLogo-16042.png");
message.setData("image/png", image);
messageStyle.addMessage(message);
builder.setStyle(messageStyle);
builder.setSmallIcon(R.mipmap.ic_launcher);
Notification notification = builder.build();

NotificationManager notifyManager =
(NotificationManager) getSystemService(
MainActivity.this.getApplicationContext().NOTIFICATION_SERVICE);

notifyManager.createNotificationChannel(channel);
notifyManager.notify("WeTest", 1, notification);

通道设置、广播和免打扰优化

Android P 中,重点做了内容丰富上的工作,同时也对 Channel 的设置方面做了一些简化处理。

Android O 版本里,首次推出了 NotificationChannel,开发者需要配置相应的 Channel,才能够推送通知給用户。用户能够更加细粒度 [v1] 的针对 App 的 Channel 选择,而不是禁止 App 的所有通知内容。

而在 Android P 中,对通知的管理做了进一步的优化,包括可以屏蔽通道组、提供新的广播类型和新的免打扰优先级。

屏蔽通道组: 用户可以在通知设置中屏蔽 App 的整个通道组。开发者可以通过 isBlocked() 来判断某个通道组是否被屏蔽了,并根据结果,不向已经被屏蔽的通道组发送任何通知。另外,开发者可以在 App 中使用新接口 getNotificationChannelGroup() 来查询当前的通道组设置。

新的广播类型:新广播类型是针对通道和通道组的功能增加的 “通道 (组) 屏蔽状态变化” 广播。开发者 App 中可以对所拥有的通道 (组) 接收广播,并根据具体广播内容作出动作。开发者可以通过 NotificationManager,查看广播相关的具体信息。针对广播的动作可以通过 Broadcasts 查看具体的方法和信息。

免打扰优先级: NotificationManager.Policy 增加了两个新的优先级常量,PRIORITY_CATEGORY_ALARMS(警告优先),PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER (媒体、系统和游戏声音优先)。

四、支持多摄像机和相机共享

近一段时间,双摄、多摄等机型纷纷面世。双摄及多摄提供了单摄像头所无法完成的能力,如无缝缩放、散景和立体视觉。Android P 在这方面也提供了系统级的 API 支持。

Android P 提供了系统 API,支持从两个或者多个物理摄像头同步获取数据流。此前 OEM 厂商提供的双摄设备多是厂商自行定制系统实现,此时 Android P 推出了 API,从系统层面上制定了 API 规范。

新的 API 提供了在不同相机之间切换逻辑数据流或混合数据流的调用能力。在捕捉延迟方面,提供新的会话参数,降低初始捕捉延迟。同时,提供相机共享能力,以解决在多种使用相机的场景下重复停止、开启相机流。闪光灯方面,Android P 增加基于显示的闪光灯支持。光学防抖方面,Android P 向开发者提供 OIS 时间戳,用于图像稳定性优化以及其他特效使用。

此外,Android P 还支持外部 USB/UVC 相机,可以使用更强大的外置摄像头模组。

五、支持图像媒体后期处理

Android P 引入了新的 ImageDecoder,该类除了支持对各种图片格式的解码、缩放、裁剪之外,其强大之处在于支持对解码后的图像做后期处理(post-process),使用该功能可以添加复杂的自定义特效,比如圆角,或是将图片放在圆形像框中。编写后期处理回调函数,你可以添加任何绘图指令实现需要的效果。

此外,Android P 原生支持 GIF 和 WebP 格式的动图,新增了 AnimatedVectorDrawable 类,并被新增的解码器类 ImageDecoder 直接支持,用法跟矢量动画类 AnimatedVectorDrawable 类似,实现方式也类似,通过新增渲染线程和工作线程,不需要在 UI 线程处理动图更新,可以说是无痛使用,非常省心。

下面通过编写代码,显示一张 gif 图,并利用后期处理机制,在图像中间绘制一个绿色的实心圆。

final ImageView image = (ImageView) findViewById(R.id.image);
File gifFile = new File("/data/local/tmp/test.gif");
if (! gifFile.exists()) {
Log.d(TAG, "gifFile is not exsited!");
return;
}

ImageDecoder.Source source = ImageDecoder.createSource(gifFile);
try {
d = ImageDecoder.decodeDrawable(source, new ImageDecoder.OnHeaderDecodedListener() {
@Override
public void onHeaderDecoded(ImageDecoder imageDecoder, final ImageDecoder.ImageInfo imageInfo, ImageDecoder.Source source) {
imageDecoder.setPostProcessor(new PostProcessor() {
@Override
public int onPostProcess(Canvas canvas) {
int w = imageInfo.getSize().getWidth();
int h = imageInfo.getSize().getHeight();
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.GREEN);
canvas.drawCircle(w/2, h/2, h/4, new Paint(paint));
return 0;
}
});
}
});
image.setVisibility(View.VISIBLE);
image.setImageDrawable(d);
} catch (IOException e){
Log.d(TAG, e.toString());
}
Button button = (Button) findViewById(R.id.buttonText);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (d != null && d instanceof AnimatedImageDrawable) {
AnimatedImageDrawable ad = (AnimatedImageDrawable) d;
if (ad.isRunning()) {
Log.d(TAG, "stop running");
ad.stop();
} else {
Log.d(TAG, "start running");
ad.start();
}
}
}
});

六、支持 HDR VP9 和 HEIF

Android P 内置了对 HDR VP9 和 HEIF(heic) 图像编码的支持。HEIF 是苹果在 iOS11 推出的一种高效压缩格式,目前在 IphoneX、Iphone 8、IPhone 8P 上已经支持。该格式的压缩率更高,但是编码该格式需要硬件的支持,解码并不需要。最新的支持库中的 HeifWriter 支持从 YUV 字节缓冲区、Surface 或是 Bitmap 类转换为 HEIF 格式的静态图像。

Android P 新引入了 MediaPlayer2,支持 DataSourceDesc 创建的播放列表。

功能优化提升一览

一、神经网络 API 1.1

在前不久发布的 Android 8.1 (API level 27) 上,Google 首次在 Android 平台上推出了神经网络 API,这意味着我们的 Android 机器智能化水平又提高了一大步。而本次 Android P,进一步丰富了神经网络的支持,不仅对之前的相关 API 进行了优化,并且提供了 9 个新的操作,为具体的数据操作方面提供了更深入的支持。

二、改进表单自动填充

Android 8.0(API 等级 26)中引入了自动填充框架,这使得在应用中填写表单变得更加容易。 Android P 引入了自动填充服务并实现了多项改进,得以在填写表单时进一步增强用户体验。

三、安全增强

Android P 引入了许多新的安全功能,包括统一的指纹验证对话框和敏感交易的高确信度的用户确认。应用程序内的指纹认证 UI 也将会更加一致。

统一的指纹验证对话框

如果第三方 APP 想要使用指纹,Android 系统框架为应用提供了指纹认证对话框,该功能可以提供统一的外观和使用体验,用户使用起来更放心。如果您的程序还在使用 FingerprintManager,现在改用 FingerprintDialog 替代吧,系统来提供对话框显示。对了,在使用 FingerprintDialog 之前,别忘了调用 hasSystemFeature() 方法检查手机设备是否支持指纹。

敏感交易的高确信度的用户确认

Android P 系统提供了受保护的确认 API,借助这组全新的 API,应用可以使用 ConfirmationDialog 对话框向用户提示,请求用户批准一条简短的声明, 该声明允许应用提醒用户,即将完成一笔敏感交易,例如支付。

如果用户接受声明,应用将会收到一条 key-hash 的消息认证码(HMAC),该签名由 TEE 产生,以保护用于输入和认证对话框的显示。该签名表示用于已经看到了声明并同意了。

硬件安全模块

Android P 还提供了 StrongBox Keymaster(强力沙盒秘钥大师),一个存储在硬件安全模块的具体实现。在这个硬件安全模块中有自己的 CPU、安全存储空间,真随机数生成器,以及额外的机制抵御应用被篡改或是未授权应用的恶意加载。当检查存储在 StrongBox Keymaster 中的密钥时,系统通过可信执行环境(TEE)确认密钥的完整性。为了降低能耗,StrongBox 支持了一组算法和不同长度的秘钥:

● RSA 2048

● AES 128 and 256

● ECDSA P-256

● HMAC-SHA256 (支持 8 字节到 64 字节任意秘钥长度)

● Triple DES 168

需要说明的是,这个机制需要硬件支持。

安全秘钥导入 KeyStore

使用新的 ASN.1 编码的秘钥格式添加导入秘钥到 Keystore,Android P 提供了额外的密码解密安全能力。之后 KeyMaster 就可以解密 KeyStore 存储的秘钥,这种工作方式使得秘钥明文永远不会出现在设备内存中。这项特性要求设备支持 Keymaster 4。

四、支持客户端侧 Android 备份加密

Android P 支持使用客户端密钥对 Android 备份进行加密。 这项隐私措施,需要设备的 PIN、图案密码或标准密码才能从用户设备备份的数据中恢复数据。

五、Accessibility 优化

为了使 App 使用更便捷,Android 在多个方面为开发者提供了易用性的优化。

Navigation semantics

Android P 在 App 的场景切换和操作上为开发者提供了很多的优化点。

Accessibility pane titles

Android P 中对 Section 提供了新的机制,被称为 accessibility pane titles, Accessibility services 能够接收这些标题的变化,使得能够对一些变化提供更加细粒度的信息。

指定 Section 的标题,可以通过 android:accessibilityPaneTitle 新属性来设置,同样运行时可以通过 setAccessibilityPaneTitle() 来设置标题。

顶部栏导航

Android P 提供了新的顶部栏导航机制,通过设置 View 实例的 android:accessibilityHeading 属性为 true,来显示逻辑标题。通过这些标题,用户就可以从一个标题导航到下一个标题,

群组导航和输出

针对屏幕阅读器,Android P 对 View 提供了新的属性 android:screenReaderFocusable 代替原有的 android:focusable 来做标记,来解决在一些场景下为了使屏幕阅读器工作而设置 View 为可获取焦点的操作。这时,屏幕阅读器需要同时关注 android:screenReaderFocusable 和 android:focusable 设置为 ture 的 View。

便捷操作

tooltips 交互

Android P 中,可以使用 getTooltipText() 去读取 tooltips 的文本内容。使用新的 ACTION_SHOW_TOOLTIP 和 ACTION_HIDE_TOOLTIP 控制 View 显示或者隐藏 tooltips。

新全局交互

Android P 在 AccessibilityService 类中提供了两个全新的操作。开发者的 Service 可以通过 GLOBAL_ACTION_LOCK_SCREEN 帮助用户锁屏,通过 GLOBAL_ACTION_TAKE_SCREENSHOT 帮助用户完成屏幕截图。

窗体改变的一些细节

Android P 优化了在 App 多窗体同步发生变化时的更新内容获取。当出现 TYPE_WINDOWS_CHANGED 时,开发者可以通过 getWindowChanges() API 获取窗体变化情况。

当多窗体发生改变时,每个窗体都会发出自己的事件,开发者可以通过 getSource() 获取到事件窗体的根 View。

如果你的 App 为 View 定义了 accessibility pane titles,UI 更新时你的 Service 就能够识别到相应的改动。当出现 TYPE_WINDOW_STATE_CHANGED 事件时,使用新方法 getContentChangeTypes() 返回的类型,就能够获取到当前窗体的变化情况。例如,现在就能够通过上述的机制,检测到一个 [v1] 窗格是否有了新标题,或者一个窗格的消失。

六、新的 Rotation 方案

旋转屏幕,是一些游戏、视频等场景必要的操作,但有一些场景,用户旋转屏幕并不是为了让应用显示从竖屏变成横屏或反过来。为了避免这种误操作,Android P 提供了新的机制,开发者可以指定屏幕不随重力感应旋转,而是用户通过一个单独的按钮自行控制屏幕显示转向。


参考文档:

https://developer.android.google.cn/preview/features.html

点击链接:http://wetest.qq.com/cloud/help/AndroidP 即可限时免费体验 Android P Preview 版本的远程调试及标准兼容功能。

如有任何问题,或对系统的建议,请联系 WeTest 小助手(QQ:800024531)。

我们会将与谷歌技术专家共同为您解答。


↙↙↙阅读原文可查看相关链接,并与作者交流