|
|
|
|
@@ -15,6 +15,7 @@
|
|
|
|
|
*/
|
|
|
|
|
package com.android.systemui.pip.phone;
|
|
|
|
|
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
import android.graphics.Rect;
|
|
|
|
|
import android.graphics.Region;
|
|
|
|
|
import android.os.Bundle;
|
|
|
|
|
@@ -26,6 +27,10 @@ import android.view.accessibility.AccessibilityWindowInfo;
|
|
|
|
|
import android.view.accessibility.IAccessibilityInteractionConnection;
|
|
|
|
|
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
|
|
|
|
|
|
|
|
|
|
import com.android.systemui.R;
|
|
|
|
|
import com.android.systemui.pip.PipSnapAlgorithm;
|
|
|
|
|
import com.android.systemui.pip.PipTaskOrganizer;
|
|
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
@@ -43,16 +48,30 @@ public class PipAccessibilityInteractionConnection
|
|
|
|
|
private static final long ACCESSIBILITY_NODE_ID = 1;
|
|
|
|
|
private List<AccessibilityNodeInfo> mAccessibilityNodeInfoList;
|
|
|
|
|
|
|
|
|
|
private Context mContext;
|
|
|
|
|
private Handler mHandler;
|
|
|
|
|
private PipMotionHelper mMotionHelper;
|
|
|
|
|
private PipTaskOrganizer mTaskOrganizer;
|
|
|
|
|
private PipSnapAlgorithm mSnapAlgorithm;
|
|
|
|
|
private Runnable mUpdateMovementBoundCallback;
|
|
|
|
|
private AccessibilityCallbacks mCallbacks;
|
|
|
|
|
|
|
|
|
|
private final Rect mNormalBounds = new Rect();
|
|
|
|
|
private final Rect mExpandedBounds = new Rect();
|
|
|
|
|
private final Rect mNormalMovementBounds = new Rect();
|
|
|
|
|
private final Rect mExpandedMovementBounds = new Rect();
|
|
|
|
|
private Rect mTmpBounds = new Rect();
|
|
|
|
|
|
|
|
|
|
public PipAccessibilityInteractionConnection(PipMotionHelper motionHelper,
|
|
|
|
|
AccessibilityCallbacks callbacks, Handler handler) {
|
|
|
|
|
public PipAccessibilityInteractionConnection(Context context, PipMotionHelper motionHelper,
|
|
|
|
|
PipTaskOrganizer taskOrganizer, PipSnapAlgorithm snapAlgorithm,
|
|
|
|
|
AccessibilityCallbacks callbacks, Runnable updateMovementBoundCallback,
|
|
|
|
|
Handler handler) {
|
|
|
|
|
mContext = context;
|
|
|
|
|
mHandler = handler;
|
|
|
|
|
mMotionHelper = motionHelper;
|
|
|
|
|
mTaskOrganizer = taskOrganizer;
|
|
|
|
|
mSnapAlgorithm = snapAlgorithm;
|
|
|
|
|
mUpdateMovementBoundCallback = updateMovementBoundCallback;
|
|
|
|
|
mCallbacks = callbacks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -78,34 +97,46 @@ public class PipAccessibilityInteractionConnection
|
|
|
|
|
// We only support one view. A request for anything else is invalid
|
|
|
|
|
boolean result = false;
|
|
|
|
|
if (accessibilityNodeId == AccessibilityNodeInfo.ROOT_NODE_ID) {
|
|
|
|
|
switch (action) {
|
|
|
|
|
case AccessibilityNodeInfo.ACTION_CLICK:
|
|
|
|
|
mHandler.post(() -> {
|
|
|
|
|
mCallbacks.onAccessibilityShowMenu();
|
|
|
|
|
});
|
|
|
|
|
result = true;
|
|
|
|
|
break;
|
|
|
|
|
case AccessibilityNodeInfo.ACTION_DISMISS:
|
|
|
|
|
mMotionHelper.dismissPip();
|
|
|
|
|
result = true;
|
|
|
|
|
break;
|
|
|
|
|
case com.android.internal.R.id.accessibilityActionMoveWindow:
|
|
|
|
|
int newX = arguments.getInt(
|
|
|
|
|
AccessibilityNodeInfo.ACTION_ARGUMENT_MOVE_WINDOW_X);
|
|
|
|
|
int newY = arguments.getInt(
|
|
|
|
|
AccessibilityNodeInfo.ACTION_ARGUMENT_MOVE_WINDOW_Y);
|
|
|
|
|
Rect pipBounds = new Rect();
|
|
|
|
|
pipBounds.set(mMotionHelper.getBounds());
|
|
|
|
|
mTmpBounds.offsetTo(newX, newY);
|
|
|
|
|
mMotionHelper.movePip(mTmpBounds);
|
|
|
|
|
result = true;
|
|
|
|
|
break;
|
|
|
|
|
case AccessibilityNodeInfo.ACTION_EXPAND:
|
|
|
|
|
mMotionHelper.expandPipToFullscreen();
|
|
|
|
|
result = true;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
// Leave result as false
|
|
|
|
|
|
|
|
|
|
// R constants are not final so this cannot be put in the switch-case.
|
|
|
|
|
if (action == R.id.action_pip_resize) {
|
|
|
|
|
if (mMotionHelper.getBounds().width() == mNormalBounds.width()
|
|
|
|
|
&& mMotionHelper.getBounds().height() == mNormalBounds.height()) {
|
|
|
|
|
setToExpandedBounds();
|
|
|
|
|
} else {
|
|
|
|
|
setToNormalBounds();
|
|
|
|
|
}
|
|
|
|
|
result = true;
|
|
|
|
|
} else {
|
|
|
|
|
switch (action) {
|
|
|
|
|
case AccessibilityNodeInfo.ACTION_CLICK:
|
|
|
|
|
mHandler.post(() -> {
|
|
|
|
|
mCallbacks.onAccessibilityShowMenu();
|
|
|
|
|
});
|
|
|
|
|
result = true;
|
|
|
|
|
break;
|
|
|
|
|
case AccessibilityNodeInfo.ACTION_DISMISS:
|
|
|
|
|
mMotionHelper.dismissPip();
|
|
|
|
|
result = true;
|
|
|
|
|
break;
|
|
|
|
|
case com.android.internal.R.id.accessibilityActionMoveWindow:
|
|
|
|
|
int newX = arguments.getInt(
|
|
|
|
|
AccessibilityNodeInfo.ACTION_ARGUMENT_MOVE_WINDOW_X);
|
|
|
|
|
int newY = arguments.getInt(
|
|
|
|
|
AccessibilityNodeInfo.ACTION_ARGUMENT_MOVE_WINDOW_Y);
|
|
|
|
|
Rect pipBounds = new Rect();
|
|
|
|
|
pipBounds.set(mMotionHelper.getBounds());
|
|
|
|
|
mTmpBounds.offsetTo(newX, newY);
|
|
|
|
|
mMotionHelper.movePip(mTmpBounds);
|
|
|
|
|
result = true;
|
|
|
|
|
break;
|
|
|
|
|
case AccessibilityNodeInfo.ACTION_EXPAND:
|
|
|
|
|
mMotionHelper.expandPipToFullscreen();
|
|
|
|
|
result = true;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
// Leave result as false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
@@ -115,6 +146,27 @@ public class PipAccessibilityInteractionConnection
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void setToExpandedBounds() {
|
|
|
|
|
float savedSnapFraction = mSnapAlgorithm.getSnapFraction(
|
|
|
|
|
new Rect(mTaskOrganizer.getLastReportedBounds()), mNormalMovementBounds);
|
|
|
|
|
mSnapAlgorithm.applySnapFraction(mExpandedBounds, mExpandedMovementBounds,
|
|
|
|
|
savedSnapFraction);
|
|
|
|
|
mTaskOrganizer.scheduleFinishResizePip(mExpandedBounds, (Rect bounds) -> {
|
|
|
|
|
mMotionHelper.synchronizePinnedStackBounds();
|
|
|
|
|
mUpdateMovementBoundCallback.run();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void setToNormalBounds() {
|
|
|
|
|
float savedSnapFraction = mSnapAlgorithm.getSnapFraction(
|
|
|
|
|
new Rect(mTaskOrganizer.getLastReportedBounds()), mExpandedMovementBounds);
|
|
|
|
|
mSnapAlgorithm.applySnapFraction(mNormalBounds, mNormalMovementBounds, savedSnapFraction);
|
|
|
|
|
mTaskOrganizer.scheduleFinishResizePip(mNormalBounds, (Rect bounds) -> {
|
|
|
|
|
mMotionHelper.synchronizePinnedStackBounds();
|
|
|
|
|
mUpdateMovementBoundCallback.run();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
|
|
|
|
|
String viewId, Region interactiveRegion, int interactionId,
|
|
|
|
|
@@ -175,7 +227,21 @@ public class PipAccessibilityInteractionConnection
|
|
|
|
|
// Do nothing.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static AccessibilityNodeInfo obtainRootAccessibilityNodeInfo() {
|
|
|
|
|
/**
|
|
|
|
|
* Update the normal and expanded bounds so they can be used for Resize.
|
|
|
|
|
*/
|
|
|
|
|
void onMovementBoundsChanged(Rect normalBounds, Rect expandedBounds, Rect normalMovementBounds,
|
|
|
|
|
Rect expandedMovementBounds) {
|
|
|
|
|
mNormalBounds.set(normalBounds);
|
|
|
|
|
mExpandedBounds.set(expandedBounds);
|
|
|
|
|
mNormalMovementBounds.set(normalMovementBounds);
|
|
|
|
|
mExpandedMovementBounds.set(expandedMovementBounds);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Update the Root node with PIP Accessibility action items.
|
|
|
|
|
*/
|
|
|
|
|
public static AccessibilityNodeInfo obtainRootAccessibilityNodeInfo(Context context) {
|
|
|
|
|
AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
|
|
|
|
|
info.setSourceNodeId(AccessibilityNodeInfo.ROOT_NODE_ID,
|
|
|
|
|
AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID);
|
|
|
|
|
@@ -183,6 +249,8 @@ public class PipAccessibilityInteractionConnection
|
|
|
|
|
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
|
|
|
|
|
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_MOVE_WINDOW);
|
|
|
|
|
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
|
|
|
|
|
info.addAction(new AccessibilityNodeInfo.AccessibilityAction(R.id.action_pip_resize,
|
|
|
|
|
context.getString(R.string.accessibility_action_pip_resize)));
|
|
|
|
|
info.setImportantForAccessibility(true);
|
|
|
|
|
info.setClickable(true);
|
|
|
|
|
info.setVisibleToUser(true);
|
|
|
|
|
@@ -193,7 +261,7 @@ public class PipAccessibilityInteractionConnection
|
|
|
|
|
if (mAccessibilityNodeInfoList == null) {
|
|
|
|
|
mAccessibilityNodeInfoList = new ArrayList<>(1);
|
|
|
|
|
}
|
|
|
|
|
AccessibilityNodeInfo info = obtainRootAccessibilityNodeInfo();
|
|
|
|
|
AccessibilityNodeInfo info = obtainRootAccessibilityNodeInfo(mContext);
|
|
|
|
|
mAccessibilityNodeInfoList.clear();
|
|
|
|
|
mAccessibilityNodeInfoList.add(info);
|
|
|
|
|
return mAccessibilityNodeInfoList;
|
|
|
|
|
|