Merge "Add TileAdapterDelegate" into rvc-qpr-dev am: e0123b0d23
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/12672565 Change-Id: I3d0d5ddad5a1df841521a328495668ce550de404
This commit is contained in:
@@ -177,6 +177,9 @@
|
|||||||
<item type="id" name="accessibility_action_controls_move_before" />
|
<item type="id" name="accessibility_action_controls_move_before" />
|
||||||
<item type="id" name="accessibility_action_controls_move_after" />
|
<item type="id" name="accessibility_action_controls_move_after" />
|
||||||
|
|
||||||
|
<item type="id" name="accessibility_action_qs_move_to_position" />
|
||||||
|
<item type="id" name="accessibility_action_qs_add_to_position" />
|
||||||
|
|
||||||
<!-- Accessibility actions for PIP -->
|
<!-- Accessibility actions for PIP -->
|
||||||
<item type="id" name="action_pip_resize" />
|
<item type="id" name="action_pip_resize" />
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -2267,23 +2267,26 @@
|
|||||||
<!-- Accessibility action for moving docked stack divider to make the bottom screen full screen [CHAR LIMIT=NONE] -->
|
<!-- Accessibility action for moving docked stack divider to make the bottom screen full screen [CHAR LIMIT=NONE] -->
|
||||||
<string name="accessibility_action_divider_bottom_full">Bottom full screen</string>
|
<string name="accessibility_action_divider_bottom_full">Bottom full screen</string>
|
||||||
|
|
||||||
<!-- Accessibility description of a QS tile while editing positions [CHAR LIMIT=NONE] -->
|
<!-- Accessibility description of action to remove QS tile on click. It will read as "Double-tap to remove tile" in screen readers [CHAR LIMIT=NONE] -->
|
||||||
<string name="accessibility_qs_edit_tile_label">Position <xliff:g id="position" example="2">%1$d</xliff:g>, <xliff:g id="tile_name" example="Wi-Fi">%2$s</xliff:g>. Double tap to edit.</string>
|
<string name="accessibility_qs_edit_remove_tile_action">remove tile</string>
|
||||||
|
|
||||||
<!-- Accessibility description of a QS tile while editing positions [CHAR LIMIT=NONE] -->
|
<!-- Accessibility action of action to add QS tile to end. It will read as "Double-tap to add tile to end" in screen readers [CHAR LIMIT=NONE] -->
|
||||||
<string name="accessibility_qs_edit_add_tile_label"><xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g>. Double tap to add.</string>
|
<string name="accessibility_qs_edit_tile_add_action">add tile to end</string>
|
||||||
|
|
||||||
<!-- Accessibility description of option to move QS tile [CHAR LIMIT=NONE] -->
|
<!-- Accessibility action for context menu to move QS tile [CHAR LIMIT=NONE] -->
|
||||||
<string name="accessibility_qs_edit_move_tile">Move <xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g></string>
|
<string name="accessibility_qs_edit_tile_start_move">Move tile</string>
|
||||||
|
|
||||||
<!-- Accessibility description of option to remove QS tile [CHAR LIMIT=NONE] -->
|
<!-- Accessibility action for context menu to add QS tile [CHAR LIMIT=NONE] -->
|
||||||
<string name="accessibility_qs_edit_remove_tile">Remove <xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g></string>
|
<string name="accessibility_qs_edit_tile_start_add">Add tile</string>
|
||||||
|
|
||||||
<!-- Accessibility action when QS tile is to be added [CHAR LIMIT=NONE] -->
|
<!-- Accessibility description when QS tile is to be moved, indicating the destination position [CHAR LIMIT=NONE] -->
|
||||||
<string name="accessibility_qs_edit_tile_add">Add <xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g> to position <xliff:g id="position" example="5">%2$d</xliff:g></string>
|
<string name="accessibility_qs_edit_tile_move_to_position">Move to <xliff:g id="position" example="5">%1$d</xliff:g></string>
|
||||||
|
|
||||||
<!-- Accessibility action when QS tile is to be moved [CHAR LIMIT=NONE] -->
|
<!-- Accessibility description when QS tile is to be added, indicating the destination position [CHAR LIMIT=NONE] -->
|
||||||
<string name="accessibility_qs_edit_tile_move">Move <xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g> to position <xliff:g id="position" example="5">%2$d</xliff:g></string>
|
<string name="accessibility_qs_edit_tile_add_to_position">Add to position <xliff:g id="position" example="5">%1$d</xliff:g></string>
|
||||||
|
|
||||||
|
<!-- Accessibility description indicating the currently selected tile's position. Only used for tiles that are currently in use [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="accessibility_qs_edit_position">Position <xliff:g id="position" example="5">%1$d</xliff:g></string>
|
||||||
|
|
||||||
<!-- Accessibility label for window when QS editing is happening [CHAR LIMIT=NONE] -->
|
<!-- Accessibility label for window when QS editing is happening [CHAR LIMIT=NONE] -->
|
||||||
<string name="accessibility_desc_quick_settings_edit">Quick settings editor.</string>
|
<string name="accessibility_desc_quick_settings_edit">Quick settings editor.</string>
|
||||||
|
|||||||
@@ -14,11 +14,8 @@
|
|||||||
|
|
||||||
package com.android.systemui.qs.customize;
|
package com.android.systemui.qs.customize;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.AlertDialog.Builder;
|
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
@@ -28,10 +25,11 @@ import android.view.View;
|
|||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.View.OnLayoutChangeListener;
|
import android.view.View.OnLayoutChangeListener;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.accessibility.AccessibilityManager;
|
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.core.view.AccessibilityDelegateCompat;
|
||||||
import androidx.core.view.ViewCompat;
|
import androidx.core.view.ViewCompat;
|
||||||
import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup;
|
import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup;
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||||
@@ -49,7 +47,6 @@ import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
|
|||||||
import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
|
import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
|
||||||
import com.android.systemui.qs.external.CustomTile;
|
import com.android.systemui.qs.external.CustomTile;
|
||||||
import com.android.systemui.qs.tileimpl.QSIconViewImpl;
|
import com.android.systemui.qs.tileimpl.QSIconViewImpl;
|
||||||
import com.android.systemui.statusbar.phone.SystemUIDialog;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -78,10 +75,10 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
|||||||
private final List<TileInfo> mTiles = new ArrayList<>();
|
private final List<TileInfo> mTiles = new ArrayList<>();
|
||||||
private final ItemTouchHelper mItemTouchHelper;
|
private final ItemTouchHelper mItemTouchHelper;
|
||||||
private final ItemDecoration mDecoration;
|
private final ItemDecoration mDecoration;
|
||||||
private final AccessibilityManager mAccessibilityManager;
|
|
||||||
private final int mMinNumTiles;
|
private final int mMinNumTiles;
|
||||||
private int mEditIndex;
|
private int mEditIndex;
|
||||||
private int mTileDividerIndex;
|
private int mTileDividerIndex;
|
||||||
|
private int mFocusIndex;
|
||||||
private boolean mNeedsFocus;
|
private boolean mNeedsFocus;
|
||||||
private List<String> mCurrentSpecs;
|
private List<String> mCurrentSpecs;
|
||||||
private List<TileInfo> mOtherTiles;
|
private List<TileInfo> mOtherTiles;
|
||||||
@@ -90,17 +87,28 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
|||||||
private Holder mCurrentDrag;
|
private Holder mCurrentDrag;
|
||||||
private int mAccessibilityAction = ACTION_NONE;
|
private int mAccessibilityAction = ACTION_NONE;
|
||||||
private int mAccessibilityFromIndex;
|
private int mAccessibilityFromIndex;
|
||||||
private CharSequence mAccessibilityFromLabel;
|
|
||||||
private QSTileHost mHost;
|
private QSTileHost mHost;
|
||||||
private final UiEventLogger mUiEventLogger;
|
private final UiEventLogger mUiEventLogger;
|
||||||
|
private final AccessibilityDelegateCompat mAccessibilityDelegate;
|
||||||
|
private RecyclerView mRecyclerView;
|
||||||
|
|
||||||
public TileAdapter(Context context, UiEventLogger uiEventLogger) {
|
public TileAdapter(Context context, UiEventLogger uiEventLogger) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mUiEventLogger = uiEventLogger;
|
mUiEventLogger = uiEventLogger;
|
||||||
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
|
|
||||||
mItemTouchHelper = new ItemTouchHelper(mCallbacks);
|
mItemTouchHelper = new ItemTouchHelper(mCallbacks);
|
||||||
mDecoration = new TileItemDecoration(context);
|
mDecoration = new TileItemDecoration(context);
|
||||||
mMinNumTiles = context.getResources().getInteger(R.integer.quick_settings_min_num_tiles);
|
mMinNumTiles = context.getResources().getInteger(R.integer.quick_settings_min_num_tiles);
|
||||||
|
mAccessibilityDelegate = new TileAdapterDelegate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
|
||||||
|
mRecyclerView = recyclerView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
|
||||||
|
mRecyclerView = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHost(QSTileHost host) {
|
public void setHost(QSTileHost host) {
|
||||||
@@ -130,7 +138,6 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
|||||||
// Remove blank tile from last spot
|
// Remove blank tile from last spot
|
||||||
mTiles.remove(--mEditIndex);
|
mTiles.remove(--mEditIndex);
|
||||||
// Update the tile divider position
|
// Update the tile divider position
|
||||||
mTileDividerIndex--;
|
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
mAccessibilityAction = ACTION_NONE;
|
mAccessibilityAction = ACTION_NONE;
|
||||||
@@ -241,14 +248,12 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setSelectableForHeaders(View view) {
|
private void setSelectableForHeaders(View view) {
|
||||||
if (mAccessibilityManager.isTouchExplorationEnabled()) {
|
final boolean selectable = mAccessibilityAction == ACTION_NONE;
|
||||||
final boolean selectable = mAccessibilityAction == ACTION_NONE;
|
view.setFocusable(selectable);
|
||||||
view.setFocusable(selectable);
|
view.setImportantForAccessibility(selectable
|
||||||
view.setImportantForAccessibility(selectable
|
? View.IMPORTANT_FOR_ACCESSIBILITY_YES
|
||||||
? View.IMPORTANT_FOR_ACCESSIBILITY_YES
|
: View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||||
: View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
view.setFocusableInTouchMode(selectable);
|
||||||
view.setFocusableInTouchMode(selectable);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -285,12 +290,11 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
|||||||
holder.mTileView.setVisibility(View.VISIBLE);
|
holder.mTileView.setVisibility(View.VISIBLE);
|
||||||
holder.mTileView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
|
holder.mTileView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
|
||||||
holder.mTileView.setContentDescription(mContext.getString(
|
holder.mTileView.setContentDescription(mContext.getString(
|
||||||
R.string.accessibility_qs_edit_tile_add, mAccessibilityFromLabel,
|
R.string.accessibility_qs_edit_tile_add_to_position, position));
|
||||||
position));
|
|
||||||
holder.mTileView.setOnClickListener(new OnClickListener() {
|
holder.mTileView.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
selectPosition(holder.getAdapterPosition(), v);
|
selectPosition(holder.getLayoutPosition());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
focusOnHolder(holder);
|
focusOnHolder(holder);
|
||||||
@@ -299,54 +303,49 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
|||||||
|
|
||||||
TileInfo info = mTiles.get(position);
|
TileInfo info = mTiles.get(position);
|
||||||
|
|
||||||
if (position > mEditIndex) {
|
final boolean selectable = 0 < position && position < mEditIndex;
|
||||||
|
if (selectable && mAccessibilityAction == ACTION_ADD) {
|
||||||
info.state.contentDescription = mContext.getString(
|
info.state.contentDescription = mContext.getString(
|
||||||
R.string.accessibility_qs_edit_add_tile_label, info.state.label);
|
R.string.accessibility_qs_edit_tile_add_to_position, position);
|
||||||
} else if (mAccessibilityAction == ACTION_ADD) {
|
} else if (selectable && mAccessibilityAction == ACTION_MOVE) {
|
||||||
info.state.contentDescription = mContext.getString(
|
info.state.contentDescription = mContext.getString(
|
||||||
R.string.accessibility_qs_edit_tile_add, mAccessibilityFromLabel, position);
|
R.string.accessibility_qs_edit_tile_move_to_position, position);
|
||||||
} else if (mAccessibilityAction == ACTION_MOVE) {
|
|
||||||
info.state.contentDescription = mContext.getString(
|
|
||||||
R.string.accessibility_qs_edit_tile_move, mAccessibilityFromLabel, position);
|
|
||||||
} else {
|
} else {
|
||||||
info.state.contentDescription = mContext.getString(
|
info.state.contentDescription = info.state.label;
|
||||||
R.string.accessibility_qs_edit_tile_label, position, info.state.label);
|
|
||||||
}
|
}
|
||||||
|
info.state.expandedAccessibilityClassName = "";
|
||||||
|
|
||||||
holder.mTileView.handleStateChanged(info.state);
|
holder.mTileView.handleStateChanged(info.state);
|
||||||
holder.mTileView.setShowAppLabel(position > mEditIndex && !info.isSystem);
|
holder.mTileView.setShowAppLabel(position > mEditIndex && !info.isSystem);
|
||||||
|
holder.mTileView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
|
||||||
|
holder.mTileView.setClickable(true);
|
||||||
|
holder.mTileView.setOnClickListener(null);
|
||||||
|
holder.mTileView.setFocusable(true);
|
||||||
|
holder.mTileView.setFocusableInTouchMode(true);
|
||||||
|
|
||||||
if (mAccessibilityManager.isTouchExplorationEnabled()) {
|
if (mAccessibilityAction != ACTION_NONE) {
|
||||||
final boolean selectable = mAccessibilityAction == ACTION_NONE || position < mEditIndex;
|
|
||||||
holder.mTileView.setClickable(selectable);
|
holder.mTileView.setClickable(selectable);
|
||||||
holder.mTileView.setFocusable(selectable);
|
holder.mTileView.setFocusable(selectable);
|
||||||
|
holder.mTileView.setFocusableInTouchMode(selectable);
|
||||||
holder.mTileView.setImportantForAccessibility(selectable
|
holder.mTileView.setImportantForAccessibility(selectable
|
||||||
? View.IMPORTANT_FOR_ACCESSIBILITY_YES
|
? View.IMPORTANT_FOR_ACCESSIBILITY_YES
|
||||||
: View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
: View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||||
holder.mTileView.setFocusableInTouchMode(selectable);
|
|
||||||
if (selectable) {
|
if (selectable) {
|
||||||
holder.mTileView.setOnClickListener(new OnClickListener() {
|
holder.mTileView.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
int position = holder.getAdapterPosition();
|
int position = holder.getLayoutPosition();
|
||||||
if (position == RecyclerView.NO_POSITION) return;
|
if (position == RecyclerView.NO_POSITION) return;
|
||||||
if (mAccessibilityAction != ACTION_NONE) {
|
if (mAccessibilityAction != ACTION_NONE) {
|
||||||
selectPosition(position, v);
|
selectPosition(position);
|
||||||
} else {
|
|
||||||
if (position < mEditIndex && canRemoveTiles()) {
|
|
||||||
showAccessibilityDialog(position, v);
|
|
||||||
} else if (position < mEditIndex && !canRemoveTiles()) {
|
|
||||||
startAccessibleMove(position);
|
|
||||||
} else {
|
|
||||||
startAccessibleAdd(position);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (position == mAccessibilityFromIndex) {
|
|
||||||
focusOnHolder(holder);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (position == mFocusIndex) {
|
||||||
|
focusOnHolder(holder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void focusOnHolder(Holder holder) {
|
private void focusOnHolder(Holder holder) {
|
||||||
@@ -360,9 +359,13 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
|||||||
int oldLeft, int oldTop, int oldRight, int oldBottom) {
|
int oldLeft, int oldTop, int oldRight, int oldBottom) {
|
||||||
holder.mTileView.removeOnLayoutChangeListener(this);
|
holder.mTileView.removeOnLayoutChangeListener(this);
|
||||||
holder.mTileView.requestFocus();
|
holder.mTileView.requestFocus();
|
||||||
|
if (mAccessibilityAction == ACTION_NONE) {
|
||||||
|
holder.mTileView.clearFocus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mNeedsFocus = false;
|
mNeedsFocus = false;
|
||||||
|
mFocusIndex = RecyclerView.NO_POSITION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,72 +373,77 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
|||||||
return mCurrentSpecs.size() > mMinNumTiles;
|
return mCurrentSpecs.size() > mMinNumTiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void selectPosition(int position, View v) {
|
private void selectPosition(int position) {
|
||||||
if (mAccessibilityAction == ACTION_ADD) {
|
if (mAccessibilityAction == ACTION_ADD) {
|
||||||
// Remove the placeholder.
|
// Remove the placeholder.
|
||||||
mTiles.remove(mEditIndex--);
|
mTiles.remove(mEditIndex--);
|
||||||
notifyItemRemoved(mEditIndex);
|
|
||||||
}
|
}
|
||||||
mAccessibilityAction = ACTION_NONE;
|
mAccessibilityAction = ACTION_NONE;
|
||||||
move(mAccessibilityFromIndex, position, v);
|
move(mAccessibilityFromIndex, position, false);
|
||||||
|
mFocusIndex = position;
|
||||||
|
mNeedsFocus = true;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showAccessibilityDialog(final int position, final View v) {
|
|
||||||
final TileInfo info = mTiles.get(position);
|
|
||||||
CharSequence[] options = new CharSequence[] {
|
|
||||||
mContext.getString(R.string.accessibility_qs_edit_move_tile, info.state.label),
|
|
||||||
mContext.getString(R.string.accessibility_qs_edit_remove_tile, info.state.label),
|
|
||||||
};
|
|
||||||
AlertDialog dialog = new Builder(mContext)
|
|
||||||
.setItems(options, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
if (which == 0) {
|
|
||||||
startAccessibleMove(position);
|
|
||||||
} else {
|
|
||||||
move(position, info.isSystem ? mEditIndex : mTileDividerIndex, v);
|
|
||||||
notifyItemChanged(mTileDividerIndex);
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).setNegativeButton(android.R.string.cancel, null)
|
|
||||||
.create();
|
|
||||||
SystemUIDialog.setShowForAllUsers(dialog, true);
|
|
||||||
SystemUIDialog.applyFlags(dialog);
|
|
||||||
dialog.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startAccessibleAdd(int position) {
|
private void startAccessibleAdd(int position) {
|
||||||
mAccessibilityFromIndex = position;
|
mAccessibilityFromIndex = position;
|
||||||
mAccessibilityFromLabel = mTiles.get(position).state.label;
|
|
||||||
mAccessibilityAction = ACTION_ADD;
|
mAccessibilityAction = ACTION_ADD;
|
||||||
// Add placeholder for last slot.
|
// Add placeholder for last slot.
|
||||||
mTiles.add(mEditIndex++, null);
|
mTiles.add(mEditIndex++, null);
|
||||||
// Update the tile divider position
|
// Update the tile divider position
|
||||||
mTileDividerIndex++;
|
mTileDividerIndex++;
|
||||||
|
mFocusIndex = mEditIndex - 1;
|
||||||
mNeedsFocus = true;
|
mNeedsFocus = true;
|
||||||
|
if (mRecyclerView != null) {
|
||||||
|
mRecyclerView.post(() -> mRecyclerView.smoothScrollToPosition(mFocusIndex));
|
||||||
|
}
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startAccessibleMove(int position) {
|
private void startAccessibleMove(int position) {
|
||||||
mAccessibilityFromIndex = position;
|
mAccessibilityFromIndex = position;
|
||||||
mAccessibilityFromLabel = mTiles.get(position).state.label;
|
|
||||||
mAccessibilityAction = ACTION_MOVE;
|
mAccessibilityAction = ACTION_MOVE;
|
||||||
|
mFocusIndex = position;
|
||||||
mNeedsFocus = true;
|
mNeedsFocus = true;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean canRemoveFromPosition(int position) {
|
||||||
|
return canRemoveTiles() && isCurrentTile(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isCurrentTile(int position) {
|
||||||
|
return position < mEditIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canAddFromPosition(int position) {
|
||||||
|
return position > mEditIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addFromPosition(int position) {
|
||||||
|
if (!canAddFromPosition(position)) return;
|
||||||
|
move(position, mEditIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeFromPosition(int position) {
|
||||||
|
if (!canRemoveFromPosition(position)) return;
|
||||||
|
TileInfo info = mTiles.get(position);
|
||||||
|
move(position, info.isSystem ? mEditIndex : mTileDividerIndex);
|
||||||
|
}
|
||||||
|
|
||||||
public SpanSizeLookup getSizeLookup() {
|
public SpanSizeLookup getSizeLookup() {
|
||||||
return mSizeLookup;
|
return mSizeLookup;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean move(int from, int to, View v) {
|
private boolean move(int from, int to) {
|
||||||
|
return move(from, to, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean move(int from, int to, boolean notify) {
|
||||||
if (to == from) {
|
if (to == from) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
CharSequence fromLabel = mTiles.get(from).state.label;
|
move(from, to, mTiles, notify);
|
||||||
move(from, to, mTiles);
|
|
||||||
updateDividerLocations();
|
updateDividerLocations();
|
||||||
if (to >= mEditIndex) {
|
if (to >= mEditIndex) {
|
||||||
mUiEventLogger.log(QSEditEvent.QS_EDIT_REMOVE, 0, strip(mTiles.get(to)));
|
mUiEventLogger.log(QSEditEvent.QS_EDIT_REMOVE, 0, strip(mTiles.get(to)));
|
||||||
@@ -477,9 +485,11 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
|||||||
return spec;
|
return spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> void move(int from, int to, List<T> list) {
|
private <T> void move(int from, int to, List<T> list, boolean notify) {
|
||||||
list.add(to, list.remove(from));
|
list.add(to, list.remove(from));
|
||||||
notifyItemMoved(from, to);
|
if (notify) {
|
||||||
|
notifyItemMoved(from, to);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Holder extends ViewHolder {
|
public class Holder extends ViewHolder {
|
||||||
@@ -491,6 +501,8 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
|||||||
mTileView = (CustomizeTileView) ((FrameLayout) itemView).getChildAt(0);
|
mTileView = (CustomizeTileView) ((FrameLayout) itemView).getChildAt(0);
|
||||||
mTileView.setBackground(null);
|
mTileView.setBackground(null);
|
||||||
mTileView.getIcon().disableAnimation();
|
mTileView.getIcon().disableAnimation();
|
||||||
|
mTileView.setTag(this);
|
||||||
|
ViewCompat.setAccessibilityDelegate(mTileView, mAccessibilityDelegate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,6 +539,46 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
|||||||
.setDuration(DRAG_LENGTH)
|
.setDuration(DRAG_LENGTH)
|
||||||
.alpha(.6f);
|
.alpha(.6f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean canRemove() {
|
||||||
|
return canRemoveFromPosition(getLayoutPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean canAdd() {
|
||||||
|
return canAddFromPosition(getLayoutPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggleState() {
|
||||||
|
if (canAdd()) {
|
||||||
|
add();
|
||||||
|
} else {
|
||||||
|
remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void add() {
|
||||||
|
addFromPosition(getLayoutPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void remove() {
|
||||||
|
removeFromPosition(getLayoutPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isCurrentTile() {
|
||||||
|
return TileAdapter.this.isCurrentTile(getLayoutPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
void startAccessibleAdd() {
|
||||||
|
TileAdapter.this.startAccessibleAdd(getLayoutPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
void startAccessibleMove() {
|
||||||
|
TileAdapter.this.startAccessibleMove(getLayoutPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean canTakeAccessibleAction() {
|
||||||
|
return mAccessibilityAction == ACTION_NONE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final SpanSizeLookup mSizeLookup = new SpanSizeLookup() {
|
private final SpanSizeLookup mSizeLookup = new SpanSizeLookup() {
|
||||||
@@ -648,7 +700,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
|||||||
to == 0 || to == RecyclerView.NO_POSITION) {
|
to == 0 || to == RecyclerView.NO_POSITION) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return move(from, to, target.itemView);
|
return move(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.systemui.qs.customize;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
|
|
||||||
|
import androidx.core.view.AccessibilityDelegateCompat;
|
||||||
|
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
|
||||||
|
|
||||||
|
import com.android.systemui.R;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessibility delegate for {@link TileAdapter} views.
|
||||||
|
*
|
||||||
|
* This delegate will populate the accessibility info with the proper actions that can be taken for
|
||||||
|
* the different tiles:
|
||||||
|
* <ul>
|
||||||
|
* <li>Add to end if the tile is not a current tile (by double tap).</li>
|
||||||
|
* <li>Add to a given position (by context menu). This will let the user select a position.</li>
|
||||||
|
* <li>Remove, if the tile is a current tile (by double tap).</li>
|
||||||
|
* <li>Move to a given position (by context menu). This will let the user select a position.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* This only handles generating the associated actions. The logic for selecting positions is handled
|
||||||
|
* by {@link TileAdapter}.
|
||||||
|
*
|
||||||
|
* In order for the delegate to work properly, the asociated {@link TileAdapter.Holder} should be
|
||||||
|
* passed along with the view using {@link View#setTag}.
|
||||||
|
*/
|
||||||
|
class TileAdapterDelegate extends AccessibilityDelegateCompat {
|
||||||
|
|
||||||
|
private static final int MOVE_TO_POSITION_ID = R.id.accessibility_action_qs_move_to_position;
|
||||||
|
private static final int ADD_TO_POSITION_ID = R.id.accessibility_action_qs_add_to_position;
|
||||||
|
|
||||||
|
private TileAdapter.Holder getHolder(View view) {
|
||||||
|
return (TileAdapter.Holder) view.getTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
|
||||||
|
super.onInitializeAccessibilityNodeInfo(host, info);
|
||||||
|
TileAdapter.Holder holder = getHolder(host);
|
||||||
|
info.setCollectionItemInfo(null);
|
||||||
|
info.setStateDescription("");
|
||||||
|
if (holder == null || !holder.canTakeAccessibleAction()) {
|
||||||
|
// If there's not a holder (not a regular Tile) or an action cannot be taken
|
||||||
|
// because we are in the middle of an accessibility action, don't create a special node.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
addClickAction(host, info, holder);
|
||||||
|
maybeAddActionAddToPosition(host, info, holder);
|
||||||
|
maybeAddActionMoveToPosition(host, info, holder);
|
||||||
|
|
||||||
|
if (holder.isCurrentTile()) {
|
||||||
|
info.setStateDescription(host.getContext().getString(
|
||||||
|
R.string.accessibility_qs_edit_position, holder.getLayoutPosition()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean performAccessibilityAction(View host, int action, Bundle args) {
|
||||||
|
TileAdapter.Holder holder = getHolder(host);
|
||||||
|
|
||||||
|
if (holder == null || !holder.canTakeAccessibleAction()) {
|
||||||
|
// If there's not a holder (not a regular Tile) or an action cannot be taken
|
||||||
|
// because we are in the middle of an accessibility action, perform the default action.
|
||||||
|
return super.performAccessibilityAction(host, action, args);
|
||||||
|
}
|
||||||
|
if (action == AccessibilityNodeInfo.ACTION_CLICK) {
|
||||||
|
holder.toggleState();
|
||||||
|
return true;
|
||||||
|
} else if (action == MOVE_TO_POSITION_ID) {
|
||||||
|
holder.startAccessibleMove();
|
||||||
|
return true;
|
||||||
|
} else if (action == ADD_TO_POSITION_ID) {
|
||||||
|
holder.startAccessibleAdd();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return super.performAccessibilityAction(host, action, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addClickAction(
|
||||||
|
View host, AccessibilityNodeInfoCompat info, TileAdapter.Holder holder) {
|
||||||
|
String clickActionString;
|
||||||
|
if (holder.canAdd()) {
|
||||||
|
clickActionString = host.getContext().getString(
|
||||||
|
R.string.accessibility_qs_edit_tile_add_action);
|
||||||
|
} else if (holder.canRemove()) {
|
||||||
|
clickActionString = host.getContext().getString(
|
||||||
|
R.string.accessibility_qs_edit_remove_tile_action);
|
||||||
|
} else {
|
||||||
|
// Remove the default click action if tile can't either be added or removed (for example
|
||||||
|
// if there's the minimum number of tiles)
|
||||||
|
List<AccessibilityNodeInfoCompat.AccessibilityActionCompat> listOfActions =
|
||||||
|
info.getActionList(); // This is a copy
|
||||||
|
int numActions = listOfActions.size();
|
||||||
|
for (int i = 0; i < numActions; i++) {
|
||||||
|
if (listOfActions.get(i).getId() == AccessibilityNodeInfo.ACTION_CLICK) {
|
||||||
|
info.removeAction(listOfActions.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessibilityNodeInfoCompat.AccessibilityActionCompat action =
|
||||||
|
new AccessibilityNodeInfoCompat.AccessibilityActionCompat(
|
||||||
|
AccessibilityNodeInfo.ACTION_CLICK, clickActionString);
|
||||||
|
info.addAction(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void maybeAddActionMoveToPosition(
|
||||||
|
View host, AccessibilityNodeInfoCompat info, TileAdapter.Holder holder) {
|
||||||
|
if (holder.isCurrentTile()) {
|
||||||
|
AccessibilityNodeInfoCompat.AccessibilityActionCompat action =
|
||||||
|
new AccessibilityNodeInfoCompat.AccessibilityActionCompat(MOVE_TO_POSITION_ID,
|
||||||
|
host.getContext().getString(
|
||||||
|
R.string.accessibility_qs_edit_tile_start_move));
|
||||||
|
info.addAction(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void maybeAddActionAddToPosition(
|
||||||
|
View host, AccessibilityNodeInfoCompat info, TileAdapter.Holder holder) {
|
||||||
|
if (holder.canAdd()) {
|
||||||
|
AccessibilityNodeInfoCompat.AccessibilityActionCompat action =
|
||||||
|
new AccessibilityNodeInfoCompat.AccessibilityActionCompat(ADD_TO_POSITION_ID,
|
||||||
|
host.getContext().getString(
|
||||||
|
R.string.accessibility_qs_edit_tile_start_add));
|
||||||
|
info.addAction(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.systemui.qs.customize;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.testing.AndroidTestingRunner;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
|
|
||||||
|
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import com.android.systemui.R;
|
||||||
|
import com.android.systemui.SysuiTestCase;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner.class)
|
||||||
|
public class TileAdapterDelegateTest extends SysuiTestCase {
|
||||||
|
|
||||||
|
private static final int MOVE_TO_POSITION_ID = R.id.accessibility_action_qs_move_to_position;
|
||||||
|
private static final int ADD_TO_POSITION_ID = R.id.accessibility_action_qs_add_to_position;
|
||||||
|
private static final int POSITION_STRING_ID = R.string.accessibility_qs_edit_position;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private TileAdapter.Holder mHolder;
|
||||||
|
|
||||||
|
private AccessibilityNodeInfoCompat mInfo;
|
||||||
|
private TileAdapterDelegate mDelegate;
|
||||||
|
private View mView;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
mView = new View(mContext);
|
||||||
|
mDelegate = new TileAdapterDelegate();
|
||||||
|
mInfo = AccessibilityNodeInfoCompat.obtain();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInfoNoSpecialActionsWhenNoHolder() {
|
||||||
|
mDelegate.onInitializeAccessibilityNodeInfo(mView, mInfo);
|
||||||
|
for (AccessibilityNodeInfoCompat.AccessibilityActionCompat action : mInfo.getActionList()) {
|
||||||
|
if (action.getId() == MOVE_TO_POSITION_ID || action.getId() == ADD_TO_POSITION_ID
|
||||||
|
|| action.getId() == AccessibilityNodeInfo.ACTION_CLICK) {
|
||||||
|
fail("It should not have special action " + action.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInfoNoSpecialActionsWhenCannotStartAccessibleAction() {
|
||||||
|
mView.setTag(mHolder);
|
||||||
|
when(mHolder.canTakeAccessibleAction()).thenReturn(false);
|
||||||
|
mDelegate.onInitializeAccessibilityNodeInfo(mView, mInfo);
|
||||||
|
for (AccessibilityNodeInfoCompat.AccessibilityActionCompat action : mInfo.getActionList()) {
|
||||||
|
if (action.getId() == MOVE_TO_POSITION_ID || action.getId() == ADD_TO_POSITION_ID
|
||||||
|
|| action.getId() == AccessibilityNodeInfo.ACTION_CLICK) {
|
||||||
|
fail("It should not have special action " + action.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoCollectionItemInfo() {
|
||||||
|
mInfo.setCollectionItemInfo(
|
||||||
|
AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(0, 1, 0, 1, false));
|
||||||
|
|
||||||
|
mDelegate.onInitializeAccessibilityNodeInfo(mView, mInfo);
|
||||||
|
assertThat(mInfo.getCollectionItemInfo()).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStateDescriptionHasPositionForCurrentTile() {
|
||||||
|
mView.setTag(mHolder);
|
||||||
|
int position = 3;
|
||||||
|
when(mHolder.getLayoutPosition()).thenReturn(position);
|
||||||
|
when(mHolder.isCurrentTile()).thenReturn(true);
|
||||||
|
when(mHolder.canTakeAccessibleAction()).thenReturn(true);
|
||||||
|
|
||||||
|
String expectedString = mContext.getString(POSITION_STRING_ID, position);
|
||||||
|
|
||||||
|
mDelegate.onInitializeAccessibilityNodeInfo(mView, mInfo);
|
||||||
|
assertThat(mInfo.getStateDescription()).isEqualTo(expectedString);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStateDescriptionEmptyForNotCurrentTile() {
|
||||||
|
mView.setTag(mHolder);
|
||||||
|
int position = 3;
|
||||||
|
when(mHolder.getLayoutPosition()).thenReturn(position);
|
||||||
|
when(mHolder.isCurrentTile()).thenReturn(false);
|
||||||
|
when(mHolder.canTakeAccessibleAction()).thenReturn(true);
|
||||||
|
|
||||||
|
mDelegate.onInitializeAccessibilityNodeInfo(mView, mInfo);
|
||||||
|
assertThat(mInfo.getStateDescription()).isEqualTo("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClickAddAction() {
|
||||||
|
mView.setTag(mHolder);
|
||||||
|
when(mHolder.canTakeAccessibleAction()).thenReturn(true);
|
||||||
|
when(mHolder.canAdd()).thenReturn(true);
|
||||||
|
when(mHolder.canRemove()).thenReturn(false);
|
||||||
|
|
||||||
|
mDelegate.onInitializeAccessibilityNodeInfo(mView, mInfo);
|
||||||
|
|
||||||
|
String expectedString = mContext.getString(R.string.accessibility_qs_edit_tile_add_action);
|
||||||
|
AccessibilityNodeInfoCompat.AccessibilityActionCompat action =
|
||||||
|
getActionForId(mInfo, AccessibilityNodeInfo.ACTION_CLICK);
|
||||||
|
assertThat(action.getLabel().toString()).contains(expectedString);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClickRemoveAction() {
|
||||||
|
mView.setTag(mHolder);
|
||||||
|
when(mHolder.canTakeAccessibleAction()).thenReturn(true);
|
||||||
|
when(mHolder.canAdd()).thenReturn(false);
|
||||||
|
when(mHolder.canRemove()).thenReturn(true);
|
||||||
|
|
||||||
|
mDelegate.onInitializeAccessibilityNodeInfo(mView, mInfo);
|
||||||
|
|
||||||
|
String expectedString = mContext.getString(
|
||||||
|
R.string.accessibility_qs_edit_remove_tile_action);
|
||||||
|
AccessibilityNodeInfoCompat.AccessibilityActionCompat action =
|
||||||
|
getActionForId(mInfo, AccessibilityNodeInfo.ACTION_CLICK);
|
||||||
|
assertThat(action.getLabel().toString()).contains(expectedString);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoClickAction() {
|
||||||
|
mView.setTag(mHolder);
|
||||||
|
when(mHolder.canTakeAccessibleAction()).thenReturn(true);
|
||||||
|
when(mHolder.canAdd()).thenReturn(false);
|
||||||
|
when(mHolder.canRemove()).thenReturn(false);
|
||||||
|
mInfo.addAction(AccessibilityNodeInfo.ACTION_CLICK);
|
||||||
|
|
||||||
|
mDelegate.onInitializeAccessibilityNodeInfo(mView, mInfo);
|
||||||
|
|
||||||
|
AccessibilityNodeInfoCompat.AccessibilityActionCompat action =
|
||||||
|
getActionForId(mInfo, AccessibilityNodeInfo.ACTION_CLICK);
|
||||||
|
assertThat(action).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddToPositionAction() {
|
||||||
|
mView.setTag(mHolder);
|
||||||
|
when(mHolder.canTakeAccessibleAction()).thenReturn(true);
|
||||||
|
when(mHolder.canAdd()).thenReturn(true);
|
||||||
|
|
||||||
|
mDelegate.onInitializeAccessibilityNodeInfo(mView, mInfo);
|
||||||
|
assertThat(getActionForId(mInfo, ADD_TO_POSITION_ID)).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoAddToPositionAction() {
|
||||||
|
mView.setTag(mHolder);
|
||||||
|
when(mHolder.canTakeAccessibleAction()).thenReturn(true);
|
||||||
|
when(mHolder.canAdd()).thenReturn(false);
|
||||||
|
|
||||||
|
mDelegate.onInitializeAccessibilityNodeInfo(mView, mInfo);
|
||||||
|
assertThat(getActionForId(mInfo, ADD_TO_POSITION_ID)).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMoveToPositionAction() {
|
||||||
|
mView.setTag(mHolder);
|
||||||
|
when(mHolder.canTakeAccessibleAction()).thenReturn(true);
|
||||||
|
when(mHolder.isCurrentTile()).thenReturn(true);
|
||||||
|
|
||||||
|
mDelegate.onInitializeAccessibilityNodeInfo(mView, mInfo);
|
||||||
|
assertThat(getActionForId(mInfo, MOVE_TO_POSITION_ID)).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoMoveToPositionAction() {
|
||||||
|
mView.setTag(mHolder);
|
||||||
|
when(mHolder.canTakeAccessibleAction()).thenReturn(true);
|
||||||
|
when(mHolder.isCurrentTile()).thenReturn(false);
|
||||||
|
|
||||||
|
mDelegate.onInitializeAccessibilityNodeInfo(mView, mInfo);
|
||||||
|
assertThat(getActionForId(mInfo, MOVE_TO_POSITION_ID)).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoInteractionsWhenCannotTakeAccessibleAction() {
|
||||||
|
mView.setTag(mHolder);
|
||||||
|
when(mHolder.canTakeAccessibleAction()).thenReturn(false);
|
||||||
|
|
||||||
|
mDelegate.performAccessibilityAction(mView, AccessibilityNodeInfo.ACTION_CLICK, null);
|
||||||
|
mDelegate.performAccessibilityAction(mView, MOVE_TO_POSITION_ID, new Bundle());
|
||||||
|
mDelegate.performAccessibilityAction(mView, ADD_TO_POSITION_ID, new Bundle());
|
||||||
|
|
||||||
|
verify(mHolder, never()).toggleState();
|
||||||
|
verify(mHolder, never()).startAccessibleAdd();
|
||||||
|
verify(mHolder, never()).startAccessibleMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClickActionTogglesState() {
|
||||||
|
mView.setTag(mHolder);
|
||||||
|
when(mHolder.canTakeAccessibleAction()).thenReturn(true);
|
||||||
|
|
||||||
|
mDelegate.performAccessibilityAction(mView, AccessibilityNodeInfo.ACTION_CLICK, null);
|
||||||
|
|
||||||
|
verify(mHolder).toggleState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddToPositionActionStartsAccessibleAdd() {
|
||||||
|
mView.setTag(mHolder);
|
||||||
|
when(mHolder.canTakeAccessibleAction()).thenReturn(true);
|
||||||
|
|
||||||
|
mDelegate.performAccessibilityAction(mView, ADD_TO_POSITION_ID, null);
|
||||||
|
|
||||||
|
verify(mHolder).startAccessibleAdd();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMoveToPositionActionStartsAccessibleMove() {
|
||||||
|
mView.setTag(mHolder);
|
||||||
|
when(mHolder.canTakeAccessibleAction()).thenReturn(true);
|
||||||
|
|
||||||
|
mDelegate.performAccessibilityAction(mView, MOVE_TO_POSITION_ID, null);
|
||||||
|
|
||||||
|
verify(mHolder).startAccessibleMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AccessibilityNodeInfoCompat.AccessibilityActionCompat getActionForId(
|
||||||
|
AccessibilityNodeInfoCompat info, int action) {
|
||||||
|
for (AccessibilityNodeInfoCompat.AccessibilityActionCompat a : info.getActionList()) {
|
||||||
|
if (a.getId() == action) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user