blob: 117296d5f6d3c7df2f52fe6514a392a575ea64ec [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.accessibility;
import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.accessibility.AccessibilityEvent;
import com.android.launcher3.CellLayout;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import java.util.List;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.customview.widget.ExploreByTouchHelper;
/**
* Helper class to make drag-and-drop in a {@link CellLayout} accessible.
*/
public abstract class DragAndDropAccessibilityDelegate extends ExploreByTouchHelper
implements OnClickListener {
protected static final int INVALID_POSITION = -1;
private static final int[] sTempArray = new int[2];
protected final CellLayout mView;
protected final Context mContext;
protected final LauncherAccessibilityDelegate mDelegate;
private final Rect mTempRect = new Rect();
public DragAndDropAccessibilityDelegate(CellLayout forView) {
super(forView);
mView = forView;
mContext = mView.getContext();
mDelegate = Launcher.getLauncher(mContext).getAccessibilityDelegate();
}
@Override
protected int getVirtualViewAt(float x, float y) {
if (x < 0 || y < 0 || x > mView.getMeasuredWidth() || y > mView.getMeasuredHeight()) {
return INVALID_ID;
}
mView.pointToCellExact((int) x, (int) y, sTempArray);
// Map cell to id
int id = sTempArray[0] + sTempArray[1] * mView.getCountX();
return intersectsValidDropTarget(id);
}
/**
* @return the view id of the top left corner of a valid drop region or
* {@link #INVALID_POSITION} if there is no such valid region.
*/
protected abstract int intersectsValidDropTarget(int id);
@Override
protected void getVisibleVirtualViews(List<Integer> virtualViews) {
// We create a virtual view for each cell of the grid
// The cell ids correspond to cells in reading order.
int nCells = mView.getCountX() * mView.getCountY();
for (int i = 0; i < nCells; i++) {
if (intersectsValidDropTarget(i) == i) {
virtualViews.add(i);
}
}
}
@Override
protected boolean onPerformActionForVirtualView(int viewId, int action, Bundle args) {
if (action == AccessibilityNodeInfoCompat.ACTION_CLICK && viewId != INVALID_ID) {
String confirmation = getConfirmationForIconDrop(viewId);
mDelegate.handleAccessibleDrop(mView, getItemBounds(viewId), confirmation);
return true;
}
return false;
}
@Override
public void onClick(View v) {
onPerformActionForVirtualView(getFocusedVirtualView(),
AccessibilityNodeInfoCompat.ACTION_CLICK, null);
}
@Override
protected void onPopulateEventForVirtualView(int id, AccessibilityEvent event) {
if (id == INVALID_ID) {
throw new IllegalArgumentException("Invalid virtual view id");
}
event.setContentDescription(mContext.getString(R.string.action_move_here));
}
@Override
protected void onPopulateNodeForVirtualView(int id, AccessibilityNodeInfoCompat node) {
if (id == INVALID_ID) {
throw new IllegalArgumentException("Invalid virtual view id");
}
node.setContentDescription(getLocationDescriptionForIconDrop(id));
node.setBoundsInParent(getItemBounds(id));
node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
node.setClickable(true);
node.setFocusable(true);
}
protected abstract String getLocationDescriptionForIconDrop(int id);
protected abstract String getConfirmationForIconDrop(int id);
private Rect getItemBounds(int id) {
int cellX = id % mView.getCountX();
int cellY = id / mView.getCountX();
LauncherAccessibilityDelegate.DragInfo dragInfo = mDelegate.getDragInfo();
mView.cellToRect(cellX, cellY, dragInfo.info.spanX, dragInfo.info.spanY, mTempRect);
return mTempRect;
}
}