Drag and drop拖放框架
android11-release 应用使用 拖放 Drag and drop
Drag and drop拖放启动
APP调用启动
拖放 Drag and drop startDragAndDrop 启动 frameworks/base/core/java/android/view/View.java frameworks\base\services\core\java\com\android\server\wm\Session.java
初始化DragState并注册InputChannel
- 初始化DragState
- 注册
drag InputChannel \DragInputEventReceiver - 通知拖放开始
mDragState.broadcastDragStartedLocked(touchX, touchY); 触发DragEvent.ACTION_DRAG_STARTED
frameworks/base/services/core/java/com/android/server/wm/DragDropController.java frameworks/base/services/core/java/com/android/server/wm/DragState.java frameworks/base/services/core/java/com/android/server/wm/WindowManagerInternal.java frameworks/base/services/core/java/com/android/server/wm/DragInputEventReceiver.java
最后notifyLocationLocked
(touchedWin != mTargetWindow) && (mTargetWindow != null) 时触发 DragEvent.ACTION_DRAG_EXITED touchedWin != null 时触发 DragEvent.ACTION_DRAG_LOCATION - 通过
ViewRootImplmpl 层层调用,result = mView.dispatchDragEvent(event) 通知APP并接受返回值 li.mOnDragListener.onDrag(this, event) 真正通知APP frameworks/base/core/java/android/view/ViewRootImpl.java frameworks/base/core/java/android/view/View.java
Drag and drop拖放启动小结:
- APP启动
startDragAndDrop ,并View.OnDragListener 监听 - 初始化
DragState 和注册drag InputChannel \DragInputEventReceiver ; - ViewRootImpl中
result = mView.dispatchDragEvent(event); 发送到View,这里注意返回值result - View中
li.mOnDragListener.onDrag(this, event) 通知到APP监听 SurfaceControl 控制显示Surface ,该显示与一般WMS显示不同
Drag and drop拖放action触发问题
public static final int ACTION_DRAG_STARTED = 1; public static final int ACTION_DRAG_LOCATION = 2; public static final int ACTION_DROP = 3; public static final int ACTION_DRAG_ENDED = 4; public static final int ACTION_DRAG_ENTERED = 5; public static final int ACTION_DRAG_EXITED = 6;
- ACTION_DRAG_STARTED
当应用调用 startDragAndDrop\startDrag 并获取拖动阴影后,视图对象的拖动事件监听器会立即收到此事件操作类型。
1 触发
上面也看到初始化registerInputChannel 完成后mDragState.broadcastDragStartedLocked(touchX, touchY) 通知完成: performDrag -> broadcastDragStartedLocked -> sendDragStartedLocked -> newWin.mClient.dispatchDragEvent(event)\dispatchDragEvent(DragEvent event) -> handleDragEvent
2 通知APP监听前操作
frameworks/base/core/java/android/view/ViewRootImpl.java handleDragEvent 中设置mCurrentDragView = null ;mDragDescription 保存 event.mClipDescription
3 result = mView.dispatchDragEvent(event) 返回值
result 无论返回 true 或 false 没有其他处理,所有没有其他影响。
- ACTION_DRAG_LOCATION
当收到 ACTION_DRAG_ENTERED 事件且拖动阴影仍在视图的边界框内时,该视图对象的拖动事件监听器会收到此事件操作类型。
1 触发
这里注册了drag InputChannel \DragInputEventReceiver ,收到ACTION_MOVE 事件调用mDragDropController.handleMotionEvent (Android 12 beta4这里没有任何操作 ),!mMuteInput 最终调用到mDragState.notifyMoveLocked 。
frameworks/base/services/core/java/com/android/server/wm/DragInputEventReceiver.java frameworks/base/services/core/java/com/android/server/wm/DragDropController.java frameworks/base/services/core/java/com/android/server/wm/DragState.java
在 DragState中notifyLocationLocked 通过touchedWin.mClient.dispatchDragEvent(evt) 调用到ViewRootImpl中handleDragEvent
流程小结:drag InputChannel \DragInputEventReceiver -> handleMotionEvent -> notifyMoveLocked \notifyLocationLocked -> touchedWin.mClient.dispatchDragEvent(evt) \dispatchDragEvent(DragEvent event) -> handleDragEvent
2 通知APP监听前操作
frameworks/base/core/java/android/view/ViewRootImpl.java
3 result = mView.dispatchDragEvent(event) 返回值
result 无论返回 true 或 false ,!event.mEventHandlerWasCalled 判断执行setDragFocus 。
- ACTION_DROP
当用户将拖动阴影释放到视图对象上时,该视图对象的拖动事件监听器会收到此事件操作类型。仅当视图对象的监听器在响应 ACTION_DRAG_STARTED 拖动事件时返回布尔值 true 时,系统才会将该操作类型发送至该监听器。如果用户将拖动阴影释放到未注册监听器的视图上或不属于当前布局的任何视图上,系统都不会发送此操作类型。
如果成功处理了放下操作,监听器应返回布尔值 true。否则,它应返回 false。
1 触发
这里注册了drag InputChannel \DragInputEventReceiver ,收到ACTION_UP \ACTION_CANCEL 事件调用mDragDropController.handleMotionEvent (Android 12 beta4这里没有任何操作 ),!mMuteInput 最终调用到mDragState.notifyDropLocked 。
在 DragState中notifyLocationLocked 通过touchedWin.mClient.dispatchDragEvent(evt) 调用到ViewRootImpl中handleDragEvent
流程小结:drag InputChannel \DragInputEventReceiver -> handleMotionEvent -> notifyMoveLocked \notifyLocationLocked -> touchedWin.mClient.dispatchDragEvent(evt) \dispatchDragEvent(DragEvent event) -> handleDragEvent
与ACTION_DRAG_LOCATION 不同的是这里超时5s执行mDragState.endDragLocked()
这里也可能不会触发DragEvent.ACTION_DROP ,closeLocked() 结束触发DragEvent.ACTION_DRAG_ENDED
2 通知APP监听前操作
frameworks/base/core/java/android/view/ViewRootImpl.java
3 result = mView.dispatchDragEvent(event) 返回true 情况
APP返回true 结束拖放closeLocked() 结束触发DragEvent.ACTION_DRAG_ENDED
- ACTION_DRAG_ENDED
当系统结束拖动操作时,视图对象的拖动事件监听器会收到此事件操作类型。
此操作类型不一定在 ACTION_DROP 事件之后。
如果系统已发送 ACTION_DROP,收到 ACTION_DRAG_ENDED 操作类型并不表示放下操作成功。
监听器必须调用 getResult() 才能获得响应 ACTION_DROP 时所返回的值。
如果未发送 ACTION_DROP 事件,getResult() 将返回 false。
1 触发
读到这里,上面可看到closeLocked() 方法触发DragEvent.ACTION_DRAG_ENDED 这里先注销drag input channel
2 通知APP监听前操作
3 result = mView.dispatchDragEvent(event) 返回值
result 无论返回 true 或 false 都重置
- ACTION_DRAG_ENTERED\ACTION_DRAG_EXITED
**ACTION_DRAG_ENTERED**当拖动阴影刚进入视图的边界框时,视图对象的拖动事件监听器会收到此事件操作类型。这是监听器在拖动阴影进入边界框时收到的第一个事件操作类型。如果监听器想继续接收此操作的拖动事件,必须向系统返回布尔值 true。
**ACTION_DRAG_EXITED**当收到 ACTION_DRAG_ENTERED 和至少一个 ACTION_DRAG_LOCATION 事件,并且用户已将拖动阴影移至视图的边界框以外时,该视图对象的拖动事件监听器会收到此事件操作类型。
1 触发
从上面看到setDragFocus 设置刷新时会触发
2 直接调用callDragEventHandler
ACTION_DRAG_ENTERED 说明返回 true,目前没有看到为什么
|