hi,粉丝朋友们:
背景
大家好!近来居然有好几个粉丝朋友居然问到了一个虚拟屏幕触摸相关的问题,还有老版本android 10上面有个车载桌面使用的ActivityView可以正常触摸的问题。
其实这个ActivityView在最新的版本已经没有了,所以以前的话没有去重点分析这个ActivityView触摸部分的原理剖析,但是发现虽然没有了ActivityView。但是很多同学还是喜欢自己在高版本又写一个类似的ActivityView。基于这个背景下,拿出老版本的ActivityView分析一下其实现原理还是有必要哈。前面的blog本身已经分析了ActivityView的显示Activity原理部分,本节就来重点分析ActvityView是怎么在系统中正常触摸的。
为了分析这个ActivityView的触摸原理,我这边特别下载了android 10的代码编译好了一个car的模拟器进行验证分析
车载桌面的当前表现
目前车载的桌面显示如下图,绿色的“”No maps …“”这个区域就是ActivityView,他属于搞了个新的虚拟Display然后启动的Activity。所以这里的就会存在在CarLauncher上面显示两个Activity,一个是桌面自己,一个是地图绿色的Activity,但是大家注意哈,这里的绿色区域的地图Activity明显属于另一个display,这里我们是知道的触摸都是每个display独立的,即多屏display显示都是有各自display的触摸节点。
但是目前画面都显示在主屏幕display0这个屏幕,所以我们触摸绿色区域,肯定触摸事件是display0的,肯定不会到虚拟display去,这个是我们的理论分析的哈,认为如果要虚拟display有事件,必须要手动注入模拟相关的触摸事件注入到虚拟display。但事实真的是这样吗?
认为绿色虚拟屏幕不可能有触摸事件接受,我们来验证一下是不是触摸没有触摸事件
为了验证,在地图容器Activity的dispatchTouchEvent有日志打印,以此来确定是否有事件到Activity。
实际上在触摸绿色区域时候,发现有对于事件:
```bash
11-13 00:29:48.738 3638 3638 I lsm11 : dispatchTouchEvent ev MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=188.97656, y[0]=107.98242, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=2719884, downTime=2719884, deviceId=0, source=0x1002, displayId=0 }11-13 00:29:48.851 3638 3638 I lsm11 : dispatchTouchEvent ev MotionEvent { action=ACTION_UP, actionButton=0, id[0]=0, x[0]=188.97656, y[0]=107.98242, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=2719996, downTime=2719884, deviceId=0, source=0x1002, displayId=0 }
看到结果是不是感觉自己被狠狠打脸了。。。。。
为啥可以收到触摸主屏幕触摸事件呢,activity明明显示在另一个display
问题追踪分析线索:
怀疑线索1:
11-13 00:29:48.738 3638 3638 I lsm11 : dispatchTouchEvent ev MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=188.97656, y[0]=107.98242, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=2719884, downTime=2719884, deviceId=0, source=0x1002, displayId=0 }
看这里触摸事件时候大家是不是发现明明这个displayId居然还是0,明显不太和逻辑是吧,,,正常触摸事件是不是应该为displayId = 1(假设虚拟屏幕是displayId = 1)
不过换着想一下这个displayId决定是inputreader,即说明在inputreader时候就认为是主屏幕事件,故立马吧方向就不用放到inputreader部分
线索2:
dumpsys input
INPUT MANAGER (dumpsys input)Input Manager State:Interactive: trueSystem UI Visibility: 0x8008Pointer Speed: 0Pointer Gestures Enabled: trueShow Touches: falsePointer Capture Enabled: falseEvent Hub State:BuiltInKeyboardId: 2Devices:-1: VirtualClasses: 0x40000023Path: <virtual>Enabled: trueDescriptor: a718a782d34bc767f4689c232d64d527998ea7fdLocation: ControllerNumber: 0UniqueId: <virtual>Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000KeyLayoutFile: /system/usr/keylayout/Generic.klKeyCharacterMapFile: /system/usr/keychars/Virtual.kcmConfigurationFile: HaveKeyboardLayoutOverlay: falseVideoDevice: <none>1: Power ButtonClasses: 0x00000001Path: /dev/input/event0Enabled: trueDescriptor: 26d13db3fa0f6bd5d05831266fb01ea6c500b88cLocation: LNXPWRBN/button/input0ControllerNumber: 0UniqueId: Identifier: bus=0x0019, vendor=0x0000, product=0x0001, version=0x0000KeyLayoutFile: /system/usr/keylayout/Generic.klKeyCharacterMapFile: /system/usr/keychars/Generic.kcmConfigurationFile: HaveKeyboardLayoutOverlay: falseVideoDevice: <none>2: qwerty2 (aka device 0 - built-in keyboard)Classes: 0x000000bdPath: /dev/input/event1Enabled: trueDescriptor: 04c0f71d9920e1e448166e8a4feebf80d1849c2fLocation: ControllerNumber: 0UniqueId: Identifier: bus=0x0019, vendor=0x0000, product=0x0000, version=0x0000KeyLayoutFile: /system/usr/keylayout/qwerty.klKeyCharacterMapFile: /system/usr/keychars/qwerty2.kcmConfigurationFile: /system/usr/idc/qwerty2.idcHaveKeyboardLayoutOverlay: falseVideoDevice: <none>3: goldfish_rotaryClasses: 0x00001000Path: /dev/input/event2Enabled: trueDescriptor: 9286b20e4aaa6bcaca619b728b030e3f7b422ee6Location: ControllerNumber: 0UniqueId: Identifier: bus=0x0019, vendor=0x0000, product=0x0000, version=0x0000KeyLayoutFile: KeyCharacterMapFile: ConfigurationFile: /vendor/usr/idc/goldfish_rotary.idcHaveKeyboardLayoutOverlay: falseVideoDevice: <none>Unattached video devices:<none>Input Reader State:Device -1: VirtualGeneration: 2IsExternal: falseAssociatedDisplayPort: <none>HasMic: falseSources: 0x00000301KeyboardType: 2Keyboard Input Mapper:Parameters:OrientationAware: falseHandlesKeyRepeat: falseKeyboardType: 2Orientation: 0KeyDowns: 0 keys currently downMetaState: 0x0DownTime: 0Device 0: qwerty2Generation: 12IsExternal: falseAssociatedDisplayPort: <none>HasMic: falseSources: 0x80011307KeyboardType: 1Motion Ranges:X: source=0x00010004, min=-1.000, max=1.000, flat=0.000, fuzz=0.167, resolution=0.000Y: source=0x00010004, min=-1.000, max=1.000, flat=0.000, fuzz=0.167, resolution=0.000PRESSURE: source=0x00010004, min=0.000, max=1.000, flat=0.000, fuzz=0.000, resolution=0.000X: source=0x00001002, min=0.000, max=799.000, flat=0.000, fuzz=0.000, resolution=0.000Y: source=0x00001002, min=0.000, max=479.000, flat=0.000, fuzz=0.000, resolution=0.000PRESSURE: source=0x00001002, min=0.000, max=1.000, flat=0.000, fuzz=0.000, resolution=0.000SIZE: source=0x00001002, min=0.000, max=1.000, flat=0.000, fuzz=0.000, resolution=0.000TOUCH_MAJOR: source=0x00001002, min=0.000, max=932.952, flat=0.000, fuzz=0.000, resolution=0.000TOUCH_MINOR: source=0x00001002, min=0.000, max=932.952, flat=0.000, fuzz=0.000, resolution=0.000TOOL_MAJOR: source=0x00001002, min=0.000, max=932.952, flat=0.000, fuzz=0.000, resolution=0.000TOOL_MINOR: source=0x00001002, min=0.000, max=932.952, flat=0.000, fuzz=0.000, resolution=0.000Switch Input Mapper:SwitchValues: 0Keyboard Input Mapper:Parameters:OrientationAware: trueHandlesKeyRepeat: falseKeyboardType: 1Orientation: 0KeyDowns: 0 keys currently downMetaState: 0x0DownTime: 0Cursor Input Mapper:Parameters:HasAssociatedDisplay: trueMode: navigationOrientationAware: trueXScale: 0.167YScale: 0.167XPrecision: 6.000YPrecision: 6.000HaveVWheel: falseHaveHWheel: falseVWheelScale: 1.000HWheelScale: 1.000Orientation: 0ButtonState: 0x00000000Down: falseDownTime: 0Touch Input Mapper (mode - direct):Parameters:GestureMode: multi-touchDeviceType: touchScreenAssociatedDisplay: hasAssociatedDisplay=true, isExternal=false, displayId=''OrientationAware: trueRaw Touch Axes:X: min=0, max=32767, flat=0, fuzz=0, resolution=0Y: min=0, max=32767, flat=0, fuzz=0, resolution=0Pressure: min=0, max=256, flat=0, fuzz=0, resolution=0TouchMajor: min=0, max=2147483647, flat=0, fuzz=0, resolution=0TouchMinor: unknown rangeToolMajor: unknown rangeToolMinor: unknown rangeOrientation: unknown rangeDistance: unknown rangeTiltX: unknown rangeTiltY: unknown rangeTrackingId: min=0, max=10, flat=0, fuzz=0, resolution=0Slot: min=0, max=9, flat=0, fuzz=0, resolution=0Calibration:touch.size.calibration: geometrictouch.pressure.calibration: physicaltouch.orientation.calibration: nonetouch.distance.calibration: nonetouch.coverage.calibration: noneAffine Transformation:X scale: 1.000X ymix: 0.000X offset: 0.000Y xmix: 0.000Y scale: 1.000Y offset: 0.000Viewport INTERNAL: displayId=0, uniqueId=local:0, port=0, orientation=0, logicalFrame=[0, 0, 800, 480], physicalFrame=[0, 0, 800, 480], deviceSize=[800, 480]SurfaceWidth: 800pxSurfaceHeight: 480pxSurfaceLeft: 0SurfaceTop: 0PhysicalWidth: 800pxPhysicalHeight: 480pxPhysicalLeft: 0PhysicalTop: 0SurfaceOrientation: 0Translation and Scaling Factors:XTranslate: 0.000YTranslate: 0.000XScale: 0.024YScale: 0.015XPrecision: 40.960YPrecision: 68.267GeometricScale: 0.020PressureScale: 0.004SizeScale: 0.000OrientationScale: 0.000DistanceScale: 0.000HaveTilt: falseTiltXCenter: 0.000TiltXScale: 0.000TiltYCenter: 0.000TiltYScale: 0.000Last Raw Button State: 0x00000000Last Raw Touch: pointerCount=0Last Cooked Button State: 0x00000000Last Cooked Touch: pointerCount=0Stylus Fusion:ExternalStylusConnected: falseExternal Stylus ID: -1External Stylus Data Timeout: 9223372036854775807External Stylus State:When: 9223372036854775807Pressure: 0.000000Button State: 0x00000000Tool Type: 0Device 1: Power ButtonGeneration: 9IsExternal: falseAssociatedDisplayPort: <none>HasMic: falseSources: 0x00000101KeyboardType: 1Keyboard Input Mapper:Parameters:OrientationAware: falseHandlesKeyRepeat: falseKeyboardType: 1Orientation: 0KeyDowns: 0 keys currently downMetaState: 0x0DownTime: 0Device 3: goldfish_rotaryGeneration: 4IsExternal: falseAssociatedDisplayPort: <none>HasMic: falseSources: 0x00400000KeyboardType: 0Motion Ranges:26: source=0x00400000, min=-1.000, max=1.000, flat=0.000, fuzz=0.000, resolution=0.791Rotary Encoder Input Mapper:HaveWheel: trueConfiguration:ExcludedDeviceNames: []VirtualKeyQuietTime: 0.0msPointerVelocityControlParameters: scale=1.000, lowThreshold=500.000, highThreshold=3000.000, acceleration=3.000WheelVelocityControlParameters: scale=1.000, lowThreshold=15.000, highThreshold=50.000, acceleration=4.000PointerGesture:Enabled: trueQuietInterval: 100.0msDragMinSwitchSpeed: 50.0px/sTapInterval: 150.0msTapDragInterval: 300.0msTapSlop: 20.0pxMultitouchSettleInterval: 100.0msMultitouchMinDistance: 15.0pxSwipeTransitionAngleCosine: 0.3SwipeMaxWidthRatio: 0.2MovementSpeedRatio: 0.8ZoomSpeedRatio: 0.3Viewports:Viewport INTERNAL: displayId=0, uniqueId=local:0, port=0, orientation=0, logicalFrame=[0, 0, 800, 480], physicalFrame=[0, 0, 800, 480], deviceSize=[800, 480]Input Classifier State:Motion Classifier:<nullptr>Input Dispatcher State:DispatchEnabled: trueDispatchFrozen: falseInputFilterEnabled: falseFocusedDisplayId: 2FocusedApplications:displayId=3, name='AppWindowToken{34ea2d9 token=Token{6cc1920 ActivityRecord{e2df023 u10 android.car.cluster/.FakeFreeNavigationActivity t1000019}}}', dispatchingTimeout=5000.000msdisplayId=2, name='AppWindowToken{7f21912 token=Token{601109d ActivityRecord{c985374 u10 com.android.car.mapsplaceholder/.MapsPlaceholderActivity t1000018}}}', dispatchingTimeout=5000.000msdisplayId=1, name='AppWindowToken{ba4478b token=Token{f67795a ActivityRecord{aba2505 u0 android.car.cluster/.MainClusterActivity t5}}}', dispatchingTimeout=5000.000msdisplayId=0, name='AppWindowToken{b53bbef token=Token{3bc30ce ActivityRecord{f6201c9 u10 com.android.car.carlauncher/.CarLauncher t1000002}}}', dispatchingTimeout=5000.000msFocusedWindows:displayId=0, name='Window{71ec913 u10 com.android.car.carlauncher/com.android.car.carlauncher.CarLauncher}'displayId=2, name='Window{36a3ea8 u10 com.android.car.mapsplaceholder/com.android.car.mapsplaceholder.MapsPlaceholderActivity}'displayId=3, name='Window{752545a u10 android.car.cluster/android.car.cluster.FakeFreeNavigationActivity}'displayId=1, name='Window{96a3c94 u0 android.car.cluster/android.car.cluster.MainClusterActivity}'TouchStates: <no displays touched>Display: 3Windows:0: name='Window{752545a u10 android.car.cluster/android.car.cluster.FakeFreeNavigationActivity}', displayId=3, portalToDisplayId=-1, paused=false, hasFocus=true, hasWallpaper=false, visible=true, canReceiveKeys=true, flags=0x01810520, type=0x00000001, layer=0, frame=[0,0][1280,520], globalScale=1.000000, windowScale=(1.000000,1.000000), touchableRegion=[0,0][1280,520], inputFeatures=0x00000000, ownerPid=3735, ownerUid=1001000, dispatchingTimeout=5000.000msDisplay: 2Windows:0: name='Window{36a3ea8 u10 com.android.car.mapsplaceholder/com.android.car.mapsplaceholder.MapsPlaceholderActivity}', displayId=2, portalToDisplayId=-1, paused=false, hasFocus=true, hasWallpaper=false, visible=true, canReceiveKeys=true, flags=0x81810120, type=0x00000001, layer=0, frame=[12,69][474,384], globalScale=1.000000, windowScale=(1.000000,1.000000), touchableRegion=[12,69][474,384], inputFeatures=0x00000000, ownerPid=3638, ownerUid=1010066, dispatchingTimeout=5000.000msDisplay: 1Windows:0: name='Window{96a3c94 u0 android.car.cluster/android.car.cluster.MainClusterActivity}', displayId=1, portalToDisplayId=-1, paused=false, hasFocus=true, hasWallpaper=false, visible=true, canReceiveKeys=true, flags=0x01810520, type=0x00000001, layer=0, frame=[0,0][1280,720], globalScale=1.000000, windowScale=(1.000000,1.000000), touchableRegion=[0,0][1280,720], inputFeatures=0x00000000, ownerPid=3472, ownerUid=1000, dispatchingTimeout=5000.000msDisplay: 0Windows:0: name='Window{263dc87 u0 CarNavigationBar}', displayId=0, portalToDisplayId=-1, paused=false, hasFocus=false, hasWallpaper=false, visible=true, canReceiveKeys=false, flags=0x01840028, type=0x000007e3, layer=0, frame=[0,396][800,480], globalScale=1.000000, windowScale=(1.000000,1.000000), touchableRegion=[0,396][800,480], inputFeatures=0x00000000, ownerPid=2020, ownerUid=10099, dispatchingTimeout=5000.000ms1: name='Window{586637c u0 StatusBar}', displayId=0, portalToDisplayId=-1, paused=false, hasFocus=false, hasWallpaper=false, visible=true, canReceiveKeys=false, flags=0x81840048, type=0x000007d0, layer=0, frame=[0,0][800,57], globalScale=1.000000, windowScale=(1.000000,1.000000), touchableRegion=[0,0][800,57], inputFeatures=0x00000000, ownerPid=2020, ownerUid=10099, dispatchingTimeout=5000.000ms2: name='Window{71ec913 u10 com.android.car.carlauncher/com.android.car.carlauncher.CarLauncher}', displayId=0, portalToDisplayId=-1, paused=false, hasFocus=true, hasWallpaper=true, visible=true, canReceiveKeys=true, flags=0x81910120, type=0x00000001, layer=0, frame=[0,0][800,480], globalScale=1.000000, windowScale=(1.000000,1.000000), touchableRegion=[0,0][800,69]|[0,69][12,384]|[474,69][800,384]|[0,384][800,480], inputFeatures=0x00000000, ownerPid=3531, ownerUid=1001000, dispatchingTimeout=5000.000ms3: name='Surface(name=ActivityViewVirtualDisplay)/@0x8f6acba', displayId=0, portalToDisplayId=2, paused=false, hasFocus=false, hasWallpaper=false, visible=true, canReceiveKeys=false, flags=0x00800028, type=0x00000000, layer=0, frame=[12,69][474,384], globalScale=1.000000, windowScale=(1.000000,1.000000), touchableRegion=[12,69][474,384], inputFeatures=0x00000000, ownerPid=1875, ownerUid=1000, dispatchingTimeout=0.000ms4: name='Window{5bed72e u10 com.android.systemui.ImageWallpaper}', displayId=0, portalToDisplayId=-1, paused=false, hasFocus=false, hasWallpaper=false, visible=true, canReceiveKeys=false, flags=0x00014318, type=0x000007dd, layer=0, frame=[0,0][963,480], globalScale=1.000000, windowScale=(2.666667,2.666667), touchableRegion=[0,0][361,180], inputFeatures=0x00000000, ownerPid=2528, ownerUid=1010099, dispatchingTimeout=5000.000ms
这里我们仔细看我们发现主屏幕display 0有一个Window:
3: name='Surface(name=ActivityViewVirtualDisplay)/@0x8f6acba', displayId=0, portalToDisplayId=2, paused=false, hasFocus=false, hasWallpaper=false, visible=true, canReceiveKeys=false, flags=0x00800028, type=0x00000000, layer=0, frame=[12,69][474,384], globalScale=1.000000, windowScale=(1.000000,1.000000), touchableRegion=[12,69][474,384], inputFeatures=0x00000000, ownerPid=1875, ownerUid=1000, dispatchingTimeout=0.000ms
这个Surface(name=ActivityViewVirtualDisplay)就是ActivityView专门创建的一个input层面的window,仔细分析他的时候发现有一个变量引起我们的注意:
portalToDisplayId=2,
明显其他窗口都是 -1,他是2,而且这个2又刚好是我们的虚拟display的Id,哈哈哈到了这里大家就是不是找到核心问题点。
原理流程分析:
寻找触摸事件接受窗口时候会根据判断这个portalToDisplayId值,如果有这个值,会重新遍历这个displayId上的window代替自己这个display的window。即实现了Surface(name=ActivityViewVirtualDisplay)/@0x8f6acba这窗口的触摸事件接受都转到了displayId = portalToDisplayId的window上:
0: name=‘Window{36a3ea8 u10 com.android.car.mapsplaceholder/com.android.car.mapsplaceholder.MapsPlaceholderActivity}’, displayId=2,
那么这个portalToDisplayId谁设置的呢?
其实是ActivityView调用的reparentDisplayContent
接下来到了wms中执行:
这里调用到了DisplayContent:
好那么今天就把ActivityView的触摸部分就原理剖析完成,弥补了网络上这块的技术空白,方便大家学习,大家想要学习更多framework高深干货技术,那就跟着马哥很多干货课程,需要的课程优惠的可以+v(androidframework007)