Make AddDesktopButton can be navigated to through keys
Add the focus outline to the button as well.
Same color, ripple effect as the ClearAllButton is applied.
Flag: com.android.window.flags.enable_multiple_desktops_frontend
com.android.window.flags.enable_multiple_desktops_backend
Bug:391875235
Test: TaskGridNavHelperTest
Change-Id: If93f86a1dce4df8ee6b1c50dfc44092dad2eafab
This commit is contained in:
@@ -29,6 +29,7 @@ import java.util.List;
|
||||
*/
|
||||
public class TaskGridNavHelper {
|
||||
public static final int CLEAR_ALL_PLACEHOLDER_ID = -1;
|
||||
public static final int ADD_DESK_PLACEHOLDER_ID = -2;
|
||||
|
||||
public static final int DIRECTION_UP = 0;
|
||||
public static final int DIRECTION_DOWN = 1;
|
||||
@@ -41,44 +42,42 @@ public class TaskGridNavHelper {
|
||||
public @interface TASK_NAV_DIRECTION {}
|
||||
|
||||
private final IntArray mOriginalTopRowIds;
|
||||
private IntArray mTopRowIds;
|
||||
private IntArray mBottomRowIds;
|
||||
private final IntArray mTopRowIds = new IntArray();
|
||||
private final IntArray mBottomRowIds = new IntArray();
|
||||
|
||||
public TaskGridNavHelper(IntArray topIds, IntArray bottomIds,
|
||||
List<Integer> largeTileIds) {
|
||||
List<Integer> largeTileIds, boolean hasAddDesktopButton) {
|
||||
mOriginalTopRowIds = topIds.clone();
|
||||
generateTaskViewIdGrid(topIds, bottomIds, largeTileIds);
|
||||
generateTaskViewIdGrid(topIds, bottomIds, largeTileIds, hasAddDesktopButton);
|
||||
}
|
||||
|
||||
private void generateTaskViewIdGrid(IntArray topRowIdArray, IntArray bottomRowIdArray,
|
||||
List<Integer> largeTileIds) {
|
||||
|
||||
int maxSize = Math.max(topRowIdArray.size(), bottomRowIdArray.size())
|
||||
+ largeTileIds.size();
|
||||
int minSize = Math.min(topRowIdArray.size(), bottomRowIdArray.size())
|
||||
+ largeTileIds.size();
|
||||
|
||||
// Add Large tile task views first at the beginning
|
||||
for (int i = 0; i < largeTileIds.size(); i++) {
|
||||
topRowIdArray.add(i, largeTileIds.get(i));
|
||||
bottomRowIdArray.add(i, largeTileIds.get(i));
|
||||
List<Integer> largeTileIds, boolean hasAddDesktopButton) {
|
||||
// Add AddDesktopButton and lage tiles to both rows.
|
||||
if (hasAddDesktopButton) {
|
||||
mTopRowIds.add(ADD_DESK_PLACEHOLDER_ID);
|
||||
mBottomRowIds.add(ADD_DESK_PLACEHOLDER_ID);
|
||||
}
|
||||
for (Integer tileId : largeTileIds) {
|
||||
mTopRowIds.add(tileId);
|
||||
mBottomRowIds.add(tileId);
|
||||
}
|
||||
|
||||
// Add row ids to their respective rows.
|
||||
mTopRowIds.addAll(topRowIdArray);
|
||||
mBottomRowIds.addAll(bottomRowIdArray);
|
||||
|
||||
// Fill in the shorter array with the ids from the longer one.
|
||||
for (int i = minSize; i < maxSize; i++) {
|
||||
if (i >= topRowIdArray.size()) {
|
||||
topRowIdArray.add(bottomRowIdArray.get(i));
|
||||
} else {
|
||||
bottomRowIdArray.add(topRowIdArray.get(i));
|
||||
}
|
||||
while (mTopRowIds.size() > mBottomRowIds.size()) {
|
||||
mBottomRowIds.add(mTopRowIds.get(mBottomRowIds.size()));
|
||||
}
|
||||
while (mBottomRowIds.size() > mTopRowIds.size()) {
|
||||
mTopRowIds.add(mBottomRowIds.get(mTopRowIds.size()));
|
||||
}
|
||||
|
||||
// Add the clear all button to the end of both arrays
|
||||
topRowIdArray.add(CLEAR_ALL_PLACEHOLDER_ID);
|
||||
bottomRowIdArray.add(CLEAR_ALL_PLACEHOLDER_ID);
|
||||
|
||||
mTopRowIds = topRowIdArray;
|
||||
mBottomRowIds = bottomRowIdArray;
|
||||
// Add the clear all button to the end of both arrays.
|
||||
mTopRowIds.add(CLEAR_ALL_PLACEHOLDER_ID);
|
||||
mBottomRowIds.add(CLEAR_ALL_PLACEHOLDER_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,13 +17,15 @@
|
||||
package com.android.quickstep.views
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.ShapeDrawable
|
||||
import android.graphics.drawable.shapes.RoundRectShape
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Rect
|
||||
import android.util.AttributeSet
|
||||
import android.widget.ImageButton
|
||||
import com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X
|
||||
import com.android.launcher3.R
|
||||
import com.android.launcher3.util.MultiPropertyFactory
|
||||
import com.android.quickstep.util.BorderAnimator
|
||||
import com.android.quickstep.util.BorderAnimator.Companion.createSimpleBorderAnimator
|
||||
|
||||
/**
|
||||
* Button for supporting multiple desktop sessions. The button will be next to the first TaskView
|
||||
@@ -55,20 +57,49 @@ class AddDesktopButton @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
multiTranslationX[TranslationX.OFFSET.ordinal].value = value
|
||||
}
|
||||
|
||||
override fun onFinishInflate() {
|
||||
super.onFinishInflate()
|
||||
private val focusBorderAnimator: BorderAnimator =
|
||||
createSimpleBorderAnimator(
|
||||
context.resources.getDimensionPixelSize(R.dimen.add_desktop_button_size),
|
||||
context.resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_border_width),
|
||||
this::getBorderBounds,
|
||||
this,
|
||||
context
|
||||
.obtainStyledAttributes(attrs, R.styleable.AddDesktopButton)
|
||||
.getColor(
|
||||
R.styleable.AddDesktopButton_focusBorderColor,
|
||||
BorderAnimator.DEFAULT_BORDER_COLOR,
|
||||
),
|
||||
)
|
||||
|
||||
background =
|
||||
ShapeDrawable().apply {
|
||||
shape =
|
||||
RoundRectShape(
|
||||
FloatArray(8) { R.dimen.add_desktop_button_size.toFloat() },
|
||||
null,
|
||||
null,
|
||||
)
|
||||
setTint(
|
||||
resources.getColor(android.R.color.system_surface_bright_light, context.theme)
|
||||
)
|
||||
var borderEnabled = false
|
||||
set(value) {
|
||||
if (field == value) {
|
||||
return
|
||||
}
|
||||
field = value
|
||||
focusBorderAnimator.setBorderVisibility(visible = field && isFocused, animated = true)
|
||||
}
|
||||
|
||||
public override fun onFocusChanged(
|
||||
gainFocus: Boolean,
|
||||
direction: Int,
|
||||
previouslyFocusedRect: Rect?,
|
||||
) {
|
||||
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect)
|
||||
if (borderEnabled) {
|
||||
focusBorderAnimator.setBorderVisibility(gainFocus, /* animated= */ true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getBorderBounds(bounds: Rect) {
|
||||
bounds.set(0, 0, width, height)
|
||||
val outlinePadding =
|
||||
context.resources.getDimensionPixelSize(R.dimen.add_desktop_button_outline_padding)
|
||||
bounds.inset(-outlinePadding, -outlinePadding)
|
||||
}
|
||||
|
||||
override fun draw(canvas: Canvas) {
|
||||
focusBorderAnimator.drawBorder(canvas)
|
||||
super.draw(canvas)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1632,6 +1632,9 @@ public abstract class RecentsView<
|
||||
taskView.setBorderEnabled(enabled);
|
||||
}
|
||||
mClearAllButton.setBorderEnabled(enabled);
|
||||
if (mAddDesktopButton != null) {
|
||||
mAddDesktopButton.setBorderEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4540,24 +4543,32 @@ public abstract class RecentsView<
|
||||
|
||||
// Init task grid nav helper with top/bottom id arrays.
|
||||
TaskGridNavHelper taskGridNavHelper = new TaskGridNavHelper(getTopRowIdArray(),
|
||||
getBottomRowIdArray(), mUtils.getLargeTaskViewIds());
|
||||
getBottomRowIdArray(), mUtils.getLargeTaskViewIds(), mAddDesktopButton != null);
|
||||
|
||||
// Get current page's task view ID.
|
||||
TaskView currentPageTaskView = getCurrentPageTaskView();
|
||||
int currentPageTaskViewId;
|
||||
final int clearAllButtonIndex = indexOfChild(mClearAllButton);
|
||||
final int addDesktopButtonIndex = indexOfChild(mAddDesktopButton);
|
||||
if (currentPageTaskView != null) {
|
||||
currentPageTaskViewId = currentPageTaskView.getTaskViewId();
|
||||
} else if (mCurrentPage == indexOfChild(mClearAllButton)) {
|
||||
} else if (mCurrentPage == clearAllButtonIndex) {
|
||||
currentPageTaskViewId = TaskGridNavHelper.CLEAR_ALL_PLACEHOLDER_ID;
|
||||
} else if (mCurrentPage == addDesktopButtonIndex) {
|
||||
currentPageTaskViewId = TaskGridNavHelper.ADD_DESK_PLACEHOLDER_ID;
|
||||
} else {
|
||||
return INVALID_PAGE;
|
||||
}
|
||||
|
||||
int nextGridPage =
|
||||
final int nextGridPage =
|
||||
taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
|
||||
return nextGridPage == TaskGridNavHelper.CLEAR_ALL_PLACEHOLDER_ID
|
||||
? indexOfChild(mClearAllButton)
|
||||
: indexOfChild(getTaskViewFromTaskViewId(nextGridPage));
|
||||
if (nextGridPage == TaskGridNavHelper.CLEAR_ALL_PLACEHOLDER_ID) {
|
||||
return clearAllButtonIndex;
|
||||
}
|
||||
if (nextGridPage == TaskGridNavHelper.ADD_DESK_PLACEHOLDER_ID) {
|
||||
return addDesktopButtonIndex;
|
||||
}
|
||||
return indexOfChild(getTaskViewFromTaskViewId(nextGridPage));
|
||||
}
|
||||
|
||||
private void runDismissAnimation(PendingAnimation pendingAnim) {
|
||||
@@ -6095,8 +6106,10 @@ public abstract class RecentsView<
|
||||
}
|
||||
|
||||
private int getFirstViewIndex() {
|
||||
final TaskView firstView;
|
||||
if (mShowAsGridLastOnLayout) {
|
||||
final View firstView;
|
||||
if (mAddDesktopButton != null) {
|
||||
firstView = mAddDesktopButton;
|
||||
} else if (mShowAsGridLastOnLayout) {
|
||||
// For grid Overview, it always start if a large tile (focused task or desktop task) if
|
||||
// they exist, otherwise it start with the first task.
|
||||
TaskView firstLargeTaskView = mUtils.getFirstLargeTaskView();
|
||||
|
||||
@@ -248,8 +248,43 @@ constructor(
|
||||
)
|
||||
|
||||
private val tempCoordinates = FloatArray(2)
|
||||
private val focusBorderAnimator: BorderAnimator?
|
||||
private val hoverBorderAnimator: BorderAnimator?
|
||||
private val focusBorderAnimator: BorderAnimator? =
|
||||
focusBorderAnimator
|
||||
?: createSimpleBorderAnimator(
|
||||
TaskCornerRadius.get(context).toInt(),
|
||||
context.resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_border_width),
|
||||
this::getThumbnailBounds,
|
||||
this,
|
||||
context
|
||||
.obtainStyledAttributes(attrs, R.styleable.TaskView, defStyleAttr, defStyleRes)
|
||||
.getColor(
|
||||
R.styleable.TaskView_focusBorderColor,
|
||||
BorderAnimator.DEFAULT_BORDER_COLOR,
|
||||
),
|
||||
)
|
||||
|
||||
private val hoverBorderAnimator: BorderAnimator? =
|
||||
hoverBorderAnimator
|
||||
?: if (enableCursorHoverStates())
|
||||
createSimpleBorderAnimator(
|
||||
TaskCornerRadius.get(context).toInt(),
|
||||
context.resources.getDimensionPixelSize(R.dimen.task_hover_border_width),
|
||||
this::getThumbnailBounds,
|
||||
this,
|
||||
context
|
||||
.obtainStyledAttributes(
|
||||
attrs,
|
||||
R.styleable.TaskView,
|
||||
defStyleAttr,
|
||||
defStyleRes,
|
||||
)
|
||||
.getColor(
|
||||
R.styleable.TaskView_hoverBorderColor,
|
||||
BorderAnimator.DEFAULT_BORDER_COLOR,
|
||||
),
|
||||
)
|
||||
else null
|
||||
|
||||
private val rootViewDisplayId: Int
|
||||
get() = rootView.display?.displayId ?: Display.DEFAULT_DISPLAY
|
||||
|
||||
@@ -519,40 +554,7 @@ constructor(
|
||||
init {
|
||||
setOnClickListener { _ -> onClick() }
|
||||
|
||||
val cursorHoverStatesEnabled = enableCursorHoverStates()
|
||||
setWillNotDraw(!cursorHoverStatesEnabled)
|
||||
context.obtainStyledAttributes(attrs, R.styleable.TaskView, defStyleAttr, defStyleRes).use {
|
||||
this.focusBorderAnimator =
|
||||
focusBorderAnimator
|
||||
?: createSimpleBorderAnimator(
|
||||
TaskCornerRadius.get(context).toInt(),
|
||||
context.resources.getDimensionPixelSize(
|
||||
R.dimen.keyboard_quick_switch_border_width
|
||||
),
|
||||
{ bounds: Rect -> getThumbnailBounds(bounds) },
|
||||
this,
|
||||
it.getColor(
|
||||
R.styleable.TaskView_focusBorderColor,
|
||||
BorderAnimator.DEFAULT_BORDER_COLOR,
|
||||
),
|
||||
)
|
||||
this.hoverBorderAnimator =
|
||||
hoverBorderAnimator
|
||||
?: if (cursorHoverStatesEnabled)
|
||||
createSimpleBorderAnimator(
|
||||
TaskCornerRadius.get(context).toInt(),
|
||||
context.resources.getDimensionPixelSize(
|
||||
R.dimen.task_hover_border_width
|
||||
),
|
||||
{ bounds: Rect -> getThumbnailBounds(bounds) },
|
||||
this,
|
||||
it.getColor(
|
||||
R.styleable.TaskView_hoverBorderColor,
|
||||
BorderAnimator.DEFAULT_BORDER_COLOR,
|
||||
),
|
||||
)
|
||||
else null
|
||||
}
|
||||
setWillNotDraw(!enableCursorHoverStates())
|
||||
}
|
||||
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
|
||||
|
||||
Reference in New Issue
Block a user