异显apk分析
在安卓的SDK中有线程的ApiDemo提供给我们去参考设计
目录为:development/samples/ApiDemos/src/com/example/android/apis/app/PresentationActivity.java
1 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { |
这是通过Button的ID去选择哪个显示设备;安卓还提供了另外两种可以获取Presentation的方法
一:通过Media router去获取首选的设备和显示presentation
1 | mMediaRouter = (MediaRouter)getSystemService(Context.MEDIA_ROUTER_SERVICE); |
除了ROUTE_TYPE_LIVE_VIDEO,还有ROUTE_TYPE_REMOTE_DISPLAY,ROUTE_TYPE_USER
二:使用displayManager获取
1 | Display[]presentationDisplays = mDisplayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); |
支持的类型如下:
综上为三种创建Presentation对象方法,一:直接指定DisplayId,创建Presentation对象;二:通过MediaRoute获取Presentation对象 三:通过displayManager获取Display对象,获取DisplayId,然后创建Presentation对象;然后调用Presentation的show函数;
接下来我们就进入framework看下这个对象和相关的show函数
Presentation&&show
Presenation结构体
1 | public Presentation(Context outerContext, Display display, int theme) { |
Presentation继承自Dialog,获取到Presentation要显示的设备后,就要将Activity的context对象和设备信息作为参数来创建Presentation对象;将设备记录在成员变量mDisplay中,将Presentation设置为不可在外部点击取消;
show流程
创建ViewRoot并将view添加到链表上
1 | public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { |
setView的作用主要有两个:一:创建InputChannel来接受输入事件;二:将Window加入到WindowManager
输入事件的传递
输入设备类型
从InputReader.h我们可以看出来,安卓将输入设备分为以下几种类型:
开关:SwitchInputMapper
震动器,严格意义上是输出设备:VibratorInputMapper
鼠标:CursorInputMapper
键盘:KeyboardInputMapper
触摸设备 TouchInputMapper,SingleTouchInputMapper,MultiTouchInputMapper,
触控笔ExternalStylusInputMapper,
游戏杆:JoystickInputMapper
input设备不同初始化参数也不一样如触摸设备的话可以配置displayId,而鼠标则只能输出到主显;
touch.displayId的配置流程
1 | services/inputflinger/InputReader.cpp |
touch.displayId的传递流程
1 | services/inputflinger/InputReader.cpp |
从软件流程分析,touchScreen类型的话是通过配置device.internal来配置TP的输入设备输出到辅显,而Pointer类型的话则是通过displayId去设置输出的方向;
idc文件配置
idc(Input Device Configuration)为输入设备配置文件,包含设备具体的配置属性,这些属性影响输入设备的行为,常见的配置有;
1 | device.internal 指定输入设备属于内置组件;还是外部链接(很可能拆卸)的外围设备;0表示外部,1表示内部 |
从代码流程上看,在双屏异触的场景下,如果是两个TP,需要配置一个为内部设备,一个为外部设备;
由于安卓的默认鼠标设备的DisplayId只能是0,如代码所示:
1 | void CursorInputMapper::sync(nsecs_t when) { |
如果想要让鼠标设备支持输出到辅显也可以改变这个displayId,并且需要修改framework/base下对于鼠标控件sprite Layer的LayerStack属性的设置;笔者的话是通过鼠标在主显响应,触摸在辅屏响应来实现双屏异显异触的验证,那么这样其实可以配置;
1 | system/usr/idc/gslX680.idc |
总结:作为应用,需要指定送显时候的displayId;作为输入设备也需要指定
参考链接
Android开发-双屏异显(Presentation)实现
Android7.1 Presentation双屏异显原理分析