根据Android R版别分析

新增 DoubleScreenMovePointerEventListener 类:

package com.android.server.wm;
​
import android.util.Log;
import android.view.MotionEvent;
import android.view.WindowManagerPolicyConstants;
​
public class DoubleScreenMovePointerEventListener implements WindowManagerPolicyConstants.PointerEventListener {
  private static final String TAG = DoubleScreenMovePointerEventListener.class.getName();
​
  private boolean shouldBeginMove = false;
  private int mPoint0FirstX = 0;
  private int mPoint1FirstX = 0;
  private int mPoint0LastX = 0;
  private int mPoint1LastX = 0;
  int START_GAP = 20; //动作触发阈值,最少移动为20个像素才能够
  private final WindowManagerService mService;
  private final DisplayContent mDisplayContent;
​
  public DoubleScreenMovePointerEventListener(WindowManagerService service, DisplayContent displayContent) {
    mService = service;
    mDisplayContent = displayContent;
   }
​
  @Override
  public void onPointerEvent(MotionEvent motionEvent) {
    Log.d(TAG, "onPointerEvent: motionEvent = " + motionEvent);
    switch (motionEvent.getActionMasked()) {
      case MotionEvent.ACTION_DOWN:
      case MotionEvent.ACTION_POINTER_DOWN:
        if (motionEvent.getPointerCount() > 1) {
          shouldBeginMove = false;
          Log.d(TAG, "onPointerEvent: motionEvent.getPointerCount() > 2 end DoubleScreenMove");
         }
        if (motionEvent.getPointerCount() == 1) {
          if (mPoint0FirstX == 0) {
            //if (mPoint0FirstX == 0 && mPoint1FirstX == 0) {
            mPoint0FirstX = (int) motionEvent.getX(0);
//             mPoint1FirstX = (int) motionEvent.getX(1);
           }
         }
        break;
      case MotionEvent.ACTION_MOVE:
        if (motionEvent.getPointerCount() == 1) {
          if (!shouldBeginMove && (motionEvent.getX(0) - mPoint0FirstX) > START_GAP) {
            // && (motionEvent.getX(1) - mPoint1FirstX) > START_GAP
            //识别了双指动作到达触发task移动条件,则调用对应mDisplayContent.doTestMoveTaskToOtherDisplay办法
            Log.d(TAG, "onPointerEvent: start DoubleScreenMove");
            shouldBeginMove = true;
            mDisplayContent.doMoveStackToDisplay();
           }
          mPoint0LastX = (int) motionEvent.getX(0);
//           mPoint1LastX = (int) motionEvent.getX(1);
         }
        break;
      case MotionEvent.ACTION_POINTER_UP:
      case MotionEvent.ACTION_UP:
        shouldBeginMove = false;
        mPoint0FirstX = mPoint1FirstX = 0;
        Log.d(TAG, "onPointerEvent: ACTION_UP end DoubleScreenMove");
        break;
     }
   }
}

新增DoubleScreenMovePointerEventListener初始化(在DisplayContent中):

final DoubleScreenMovePointerEventListener mPointerEventListener;
​
DisplayContent(Display display, RootWindowContainer root) {
  ……………………
  mTapDetector = new TaskTapPointerEventListener(mWmService, this);
  mPointerEventListener = new DoubleScreenMovePointerEventListener(mWmService,this);
  registerPointerEventListener(mTapDetector);
  registerPointerEventListener(mPointerEventListener);
  registerPointerEventListener(mWmService.mMousePositionTracker);
  ……………………
}

修正DisplayContent,新增doMoveStackToDisplay()办法:

public void doMoveStackToDisplay() {
  DisplayContent otherDisplay = null;
  if (mRootWindowContainer.getChildCount() >= 2) {
    otherDisplay = (mRootWindowContainer.getChildAt(0) == this)
      ? mRootWindowContainer.getChildAt(1) : mRootWindowContainer.getChildAt(0);
   }
  if (otherDisplay != this && otherDisplay != null) {
    int topStackId = 0;
    try {
      Task topStack = getTopStack();
      if (topStack.isActivityTypeHome()) {
        Log.d(TAG, "doMoveStackToDisplay: isActivityTypeHome");
        return;
       }
      topStackId = topStack.mTaskId;
      mRootWindowContainer.moveStackToDisplay(topStackId, otherDisplay.mDisplayId, true);
     } catch (Exception ex) {
      Log.d(TAG, "doMoveStackToDisplay: exception = " + ex);
     }
   }
}

参考:blog.csdn.net/learnframew…