Videostrong嵌入式板卡 VS-RK3288双屏异显使用说明
1 简介
本文主要介绍了RockChip(以下简称RK) SDK 平台上支持的异显方案,包括系统 API、 补丁、内核配置方法等,适用于以下 SDK 平台:
RK3188 Android4.4 RK3188 Android5.1
RK3288 Android4.4 RK3288 Android5.1
2 系统 API
RK 双屏异显方案有两种方式:Android Presentation 和 RK dualscreen。Android
Presentation 是Google 提供的双屏方案,实现了 View 级别的VOP 派发,逻辑均在同一个 APP 上进行控制;RK dualscreen则是实现了APP级别的VOP派发,异显的两部分分别是不同的APP。Presentation 比较适用于对自身需求进行深入定制的方案,RK dualscreen 在满足深入定制方案下,也支持,快速集成多方 APP,进行功能整合。两者各有优缺点,也能够进行互补。
2.1 Android Presentation
2.1.1 API 介绍
官方 API 以及示例说明文档:
Presentation 是google 官方提供的一个特殊的dialog 类型,用来将特定内容显示到其他非
主屏显示器上。它在创建时,需要绑定显示屏,并根据这个目标显示屏以及其大小来配置 context
和 resource。目前系统提供了两种方式来与目标显示屏进行绑定。
1. 通过 MediaRouter 接口获取并绑定:
MediaRouter mediaRouter =(MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
MediaRouter.RouteInfo route = mediaRouter.getSelectedRoute();
if(route !=null){
Display presentationDisplay = route.getPresentationDisplay();
if(presentationDisplay !=null){
Presentation presentation =newMyPresentation(context, presentationDisplay);
presentation.show();
}
}
2. 通过DisplayManager 接口获取并绑定:
DisplayManager displayManager =(DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
Display[] presentationDisplays = displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); if(presentationDisplays.length >0){
// If there is more than one suitable presentation display, then we could consider
// giving the user a choice. For this example, we simply choose the first display
// which is the one the system recommends as the preferred presentation display.
Display display = presentationDisplays[0];
Presentation presentation =new MyPresentation(context, presentationDisplay);
presentation.show();
}
MediaRouter 和 DisplayManager 接口不在此处详细介绍。
Presentation 的接口使用简单,功能明确,主要接口如下:
1. 构造接口
(1) Presentation(Context outerContext,Display display)
接口说明:
实例一个使用默认主题,绑定到目标 display 上的Presentation 对象。
参数说明:
outerContext:application 的context 对象;
display:要绑定的目标 display,可以通过上述介绍的 MediaRouter 和 DisplayManager 接口获取。
(2) Presentation(Context outerContext, Display display, int theme)
接口说明:
实例一个使用特定主题,并绑定到目标display 上的Presentation 对象。
参数说明:
outerContext:application 的context 对象;
display:要绑定的目标 display,可通过上述介绍的 MediaRouter 和DisplayManager 接 口获取;
theme:窗口使用的主题资源。
2. 方法接口
(1) Display getDisplay()
接口说明:
获取当前presentation 显示所在的目标屏。
(2) Resources getResources()
接口说明:
获取用于当前presentation 的Resources 对象。
(3) void onDisplayChanged()
接口说明:
当 presentation 绑定的display 发生变化(如大小、方向等)时,系统会回调此接口,并且
系统将自动调用cancel()接口,关闭此presentation。
(4) void onDisplayRemoved()
接口说明:
当 presentation 绑定的display 被移除时,系统会回调此接口,并在此之后,系统会自动调
用 cancel()接口,关闭此presentation。
(5) void show()
接口说明:
用 于 显 示 此 presentation , 如 果 显 示 设 备 无 法 找 到 , 调 用 此 接 口 , 将 抛 出
WindowManager.InvalidDisplayException 异常。
(6) void onStart()
接口说明:
当此presentation 启动后,会调用此接口,类似activity 的onStart。
(7) void onStop()
接口说明:
当此presentation 正在走stop 流程时,将会调用到此接口,类似activity 的 onStop。
2.1.2 Presentation 示例
谷歌官方提供了ApiDemo,用来展示各个 API 的使用,presentation 在源码中的范例路径为:
development/samples/ApiDemos/./src/com/example/android/apis/app/Presentation Activity.java。
关键代码(红色字体)介绍如下:
1. 获取目标显示设备:
public void updateContents() {
clear();
String displayCategory = getDisplayCategory();
Display[] displays = mDisplayManager.getDisplays(displayCategory);
addAll(displays);
Log.d(TAG, "There are currently " + displays.length + " displays connected.");
for (Display display : displays) {
Log.d(TAG, "" + display);
}
}
private String getDisplayCategory() {
return mShowAllDisplaysCheckbox.isChecked() ? null :
DisplayManager.DISPLAY_CATEGORY_PRESENTATION;
}
通过DisplayManager 接口获取PRESENTATION 类型的显示设备,添加到队列当中并绑定到各个View 当中。
2. 点击CheckItem,创建Presentation,并显示:
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView == mShowAllDisplaysCheckbox) {
// Show all displays checkbox was toggled.
mDisplayListAdapter.updateContents();
} else {
//Display item checkbox was toggled.
final Display display = (Display)buttonView.getTag();
if (isChecked) {
PresentationContents contents = new PresentationContents(getNextPhoto());
showPresentation(display, contents);
} else {
hidePresentation(display);
}
}
}
通过 View 的setTag 绑定对象的方法,将display 对象绑定到具体View 当中,并在需要时,
通过getTag 获取对应的display 对象。
private void showPresentation(Display display, PresentationContents contents) {
final int displayId = display.getDisplayId();
if (mActivePresentations.get(displayId) != null) {
return;
}
Log.d(TAG, "Showing presentation photo #" + contents.photo + " on display #" + displayId + ".");
DemoPresentation presentation = new DemoPresentation(this, display, contents);
presentation.show();
presentation.setOnDismissListener(mOnDismissListener);
mActivePresentations.put(displayId, presentation);
}
在范例中自定义了一个 Presentation 类,此处通过调用自定义的 Presentation,并显式调用 show 方法,将此Presentation 显示到对应的 display 上。此处的PresentationContents 只是自定义了一个数据的封装方式,传给 Presentation,实际使用当中,可以根据项目需要,或者通过其他方式给显示的数据即可,不需要也创建这类对象。 3. 自定义 Presentation 类:
private final class DemoPresentation extends Presentation {
final PresentationContents mContents;
public DemoPresentation(Context context, Display display, PresentationContents contents) {
super(context, display);
mContents = contents;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// Be sure to call the super class.
super.onCreate(savedInstanceState);
// Get the resources for the context of the presentation.
// Notice that we are getting the resources from the context of the presentation.
Resources r = getContext().getResources();
// Inflate the layout.
setContentView(R.layout.presentation_content);
final Display display = getDisplay();
final int displayId = display.getDisplayId();
final int photo = mContents.photo;
// Show a caption to describe what's going on.
TextView text = (TextView)findViewById(R.id.text);
text.setText(r.getString(R.string.presentation_photo_text, photo, displayId, display.getName()));
// Show a n image for visual interest.
ImageView image = (ImageView)findViewById(R.id.image);
image.setImageDrawable(r.getDrawable(PHOTOS[photo]));
GradientDrawable drawable = new GradientDrawable();
drawable.setShape(GradientDrawable.RECTANGLE);
drawable.setGradientType(GradientDrawable.RADIAL_GRADIENT);
// Set the background to a random gradient.
Point p = new Point();
getDisplay().getSize(p);
drawable.setGradientRadius(Math.max(p.x, p.y) / 2);
drawable.setColors(mContents.colors);
findViewById(android.R.id.content).setBackground(drawable);
}
}
如上,可看出 Presentation 跟 Activity 的继承类似,在构造中调用父类构造方法,在onCreate 中调用 setContentView 方法设置显示的 View 布局。以上便是Android Presentation 的大体介绍,总体上来说,使用比较容易,其是Dialog 类的子类,继承和使用与 activity 类似,比较重要的一个步骤是如何获取要绑定的 display 对象, 实现了View 级别的vop 派发。
2.2 RK DualScreen
RK DualScreen 主要区别与android presentation,在于它实现了应用的派发,允许厂商快速根据现有的app 功能,进行模块的集成,减少开发周期和研发成本。
2.2.1 API 介绍
以下新增API 主要是在框架中的 Context 以及Activity 类中添加,实际使用过程中要注意实
例的对象。
(1) public void setDualScreen(boolean enable) Context 类
接口说明:
此接口用来开启/关闭系统的双屏异显功能模块;
参数说明:
true:打开双屏异显功能;
false:关闭双屏异显功能。
注意:
由于此接口需要进行 update config,因此要求app 需要集成如下:
Permission:
AndroidManifest.xml:
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
System share uid:
AndroidManifest.xml:
android:sharedUserId="android.uid.system"
Android.mk:
LOCAL_CERTIFICATE := platform
LOCAL_SDK_VERSION := current
(2) public void moveAppToDisplay(int id) Activity 类
接口说明:
用于将当前应用移动到指定的display id 设备上,使用此接口,开发厂商需要做好副屏的 APP管理,避免滞留太多的 APP 在副屏,导致出现一些性能或者管理混乱问题。
参数说明:
Id: 目标display 的id。取值范围:当前系统包含的所有显示设备的 ID 值。
(3) public void syncDualDisplay() Activity 类
接口说明:
用于同步显示状态,将异显的状态同步回同显状态;
(4) public void moveExtendDisplay() Activity 类
接口说明:
此接口是RK 内部框架集成在手势操作上的方法,与moveAppToDisplay 接口的主要区别在于,此接口流程上添加了将副屏上的应用个数控制在 1 个,即,当移动新的APP 到副屏时,会将 副屏旧的APP 移动至主屏。
2.2.2 RockChip DualScreen 接口使用示例
示例代码参见补丁中的 Demo\RKDualScreenDemo.tar.gz 工程。该工程,主要演示的功能为:获取 display 列表并显示,用户点击副屏(当前在主屏,因此点击主屏框架不做处理)id
后,应用调用接口显示到副屏,延迟 4s 后自动调用切换到主屏,延迟 4s 调用框架异显接口(带 app 个数控制),延迟4s 后会再调用同步接口,同步状态为同显。
关键代码见如下:
1. 打开双屏异显功能
public void openDualScreen(View view) {
mContext.setDualScreen(true);
}
2. 获取显示列表
public void updateContents() {
clear();
Display[] displays = mDisplayManager.getDisplays(null);
addAll(displays);
Log.d(TAG, "There are currently " + displays.length + " displays connected.");
for (Display display : displays) {
Log.d(TAG, "" + display);
}
notifyDataSetChanged();
}
3. 点击 listview,调用接口将app 派发到对应 display 设备上:
private final OnItemClickListener itemClickListener = new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
int displayid = ((ViewHolder)view.getTag()).displayid;
Log.e(TAG, "click list position = " + position + ", displayId = "+ displayid);
((MainActivity)MainActivity.this).moveAppToDisplay(displayid);
mHandler.sendEmptyMessageDelayed(MOVE_TO_DISPLAY_0, 4000);
}
};
4. 移动当前应用到主屏:
case MOVE_TO_DISPLAY_0:
Log.d(TAG, "MOVE BACK TO #0");
((MainActivity)MainActivity.this).moveAppToDisplay(0);
mTextView.setText("move to display:0");
mHandler.sendEmptyMessageDelayed(MOVE_EXTEND_DISPLAY, 4000);
break;
主屏默认ID 为0,我们这里直接写0,实际当中可以通过Display 对象进行判断。
5. 移动当前应用到外部显示设备:
case MOVE_EXTEND_DISPLAY:
Log.d(TAG, "MOVE TO EXTEND DISPLAY"); ((MainActivity)MainActivity.this).moveExtendDisplay();
mTextView.setText("move to display:EXTEND DISPLAY");
mHandler.sendEmptyMessageDelayed(SYNC_DUAL_SCREEN, 4000);
break;
此接口为RK 框架集成的手势操作的接口,自带管理副屏应用,限制副屏应用个数为1 个。
6. 将状态同步为同显状态:
case SYNC_DUAL_SCREEN:
Log.d(TAG, "SYNC BACK");
mTextView.setText("move to display:SYNC");
((MainActivity)MainActivity.this).syncDualDisplay();
break;
7. 关闭双屏异显功能:
public void closeDualScreen(View view) {
mContext.setDualScreen(false);
}
3 补丁与配置
3.1 Android
3.1.1 RK3288 Android 5.1
1. 基于最新SDK 打上补丁frameworks_base_dualscreen_api-last.patch。
2. 使 用 双 LCD 屏 时 , 请 在 /hardware/rockchip/hwcomposer 打 上 补 丁32885.1-hardware-rockchip-hwcomposer-base-on-c38e733b3.patch , 并 在 build.prop 里添加属性ro.htg.force=1。
3.1.2 RK3288 Android 4.4
1. 单 LCD 屏加 HDMI,请用 repo 同步最新代码,然后依次打上 RK3288/4.4 目录下的 两个补丁:
(1) fix_hwc_can't_be_patched_after_pull_source_code.7z
(2) [RK3288_Android4.4.4-SDK]双屏双显_Patch_V1.1.7z
2. 双 LCD 屏时,在1)基础上,使用hwcomposer_rga_force_htg.tar 替换工程中的源 码目录hardware/rk29/libhwcomposer。
3.1.3 RK3188 Android 5.1
1. 请基于最新SDK 打上补丁 frameworks_base_dualscreen_api-last.patch。
2. SDK 默认支持 LCD + HDMI 双显场景。
3. 双 LCD 屏场景,请将 patch/rk3188/5.1/ hwcomposer.rk30board.so 替换工程中的hwcomposer.rk30board.so,并在 build.prop 里添加属性ro.htg.force=1。
3.1.4 RK3188 Android 4.4
打上补丁RK3188/4.4/ RK3188_4.4_dual_screen.7z。
3.2 Kernel Driver
内核驱动根据安卓版本以及平台的不同会做区分。
3.2.1 RK3288 Android 5.1
1. rk3288 支持的显示接口可以任意组合。
2. 双屏异显时,一个显示接口当主屏,另一个当副屏;主副屏由板级 dts 文件确定,启动后无法动态更改;
3. 当两路显示接口显示不同分辨率时,rk3288 只能为一路显示接口提供精确时钟,另一路 显示接口时钟会有微小频偏;
更多查看文件:
3288双屏双显使用说明 V1.3-20161116.pdf
(699.32 KB)
|