Merge "Fix the GAR issue of all the icons on A11y FM have no meaningful A11y label." into sc-dev
This commit is contained in:
@@ -24,6 +24,7 @@ import static com.android.internal.accessibility.util.ShortcutUtils.optInValueTo
|
||||
import static com.android.internal.accessibility.util.ShortcutUtils.optOutValueFromSettings;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
@@ -33,6 +34,7 @@ import android.view.accessibility.AccessibilityManager.ShortcutType;
|
||||
import com.android.internal.accessibility.common.ShortcutConstants;
|
||||
import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
|
||||
import com.android.internal.accessibility.dialog.TargetAdapter.ViewHolder;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* Abstract base class for creating various target related to accessibility service,
|
||||
@@ -51,7 +53,8 @@ public abstract class AccessibilityTarget implements TargetOperations, OnTargetS
|
||||
private Drawable mIcon;
|
||||
private String mKey;
|
||||
|
||||
AccessibilityTarget(Context context, @ShortcutType int shortcutType,
|
||||
@VisibleForTesting
|
||||
public AccessibilityTarget(Context context, @ShortcutType int shortcutType,
|
||||
@AccessibilityFragmentType int fragmentType, boolean isShortcutSwitched, String id,
|
||||
CharSequence label, Drawable icon, String key) {
|
||||
mContext = context;
|
||||
@@ -103,6 +106,16 @@ public abstract class AccessibilityTarget implements TargetOperations, OnTargetS
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the state description of this feature target.
|
||||
*
|
||||
* @return the state description
|
||||
*/
|
||||
@Nullable
|
||||
public CharSequence getStateDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setShortcutEnabled(boolean enabled) {
|
||||
mShortcutEnabled = enabled;
|
||||
}
|
||||
|
||||
@@ -51,10 +51,14 @@ class ToggleAccessibilityServiceTarget extends AccessibilityServiceTarget {
|
||||
final boolean isEditMenuMode =
|
||||
shortcutMenuMode == ShortcutMenuMode.EDIT;
|
||||
holder.mStatusView.setVisibility(isEditMenuMode ? View.GONE : View.VISIBLE);
|
||||
holder.mStatusView.setText(getStateDescription());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getStateDescription() {
|
||||
final int statusResId = isAccessibilityServiceEnabled(getContext(), getId())
|
||||
? R.string.accessibility_shortcut_menu_item_status_on
|
||||
: R.string.accessibility_shortcut_menu_item_status_off;
|
||||
holder.mStatusView.setText(getContext().getString(statusResId));
|
||||
return getContext().getString(statusResId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,11 +48,15 @@ class ToggleAllowListingFeatureTarget extends AccessibilityTarget {
|
||||
final boolean isEditMenuMode =
|
||||
shortcutMenuMode == ShortcutMenuMode.EDIT;
|
||||
holder.mStatusView.setVisibility(isEditMenuMode ? View.GONE : View.VISIBLE);
|
||||
holder.mStatusView.setText(getStateDescription());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getStateDescription() {
|
||||
final int statusResId = isFeatureEnabled()
|
||||
? R.string.accessibility_shortcut_menu_item_status_on
|
||||
: R.string.accessibility_shortcut_menu_item_status_off;
|
||||
holder.mStatusView.setText(getContext().getString(statusResId));
|
||||
return getContext().getString(statusResId);
|
||||
}
|
||||
|
||||
private boolean isFeatureEnabled() {
|
||||
|
||||
@@ -2729,6 +2729,8 @@
|
||||
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half">Move to edge and hide</string>
|
||||
<!-- Action in accessibility menu to move the accessibility floating button out the edge and show. [CHAR LIMIT=36]-->
|
||||
<string name="accessibility_floating_button_action_move_out_edge_and_show">Move out edge and show</string>
|
||||
<!-- Action in accessibility menu to toggle on/off the accessibility feature. [CHAR LIMIT=30]-->
|
||||
<string name="accessibility_floating_button_action_double_tap_to_toggle">toggle</string>
|
||||
|
||||
<!-- Device Controls strings -->
|
||||
<!-- Device Controls empty state, title [CHAR LIMIT=30] -->
|
||||
|
||||
@@ -70,9 +70,16 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
|
||||
}
|
||||
};
|
||||
|
||||
private final ContentObserver mEnabledA11yServicesContentObserver =
|
||||
new ContentObserver(mHandler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
mMenuView.onEnabledFeaturesChanged();
|
||||
}
|
||||
};
|
||||
|
||||
public AccessibilityFloatingMenu(Context context) {
|
||||
mContext = context;
|
||||
mMenuView = new AccessibilityFloatingMenuView(context);
|
||||
this(context, new AccessibilityFloatingMenuView(context));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -153,11 +160,17 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
|
||||
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY),
|
||||
/* notifyForDescendants */ false, mFadeOutContentObserver,
|
||||
UserHandle.USER_CURRENT);
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.Secure.getUriFor(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES),
|
||||
/* notifyForDescendants */ false,
|
||||
mEnabledA11yServicesContentObserver, UserHandle.USER_CURRENT);
|
||||
}
|
||||
|
||||
private void unregisterContentObservers() {
|
||||
mContext.getContentResolver().unregisterContentObserver(mContentObserver);
|
||||
mContext.getContentResolver().unregisterContentObserver(mSizeContentObserver);
|
||||
mContext.getContentResolver().unregisterContentObserver(mFadeOutContentObserver);
|
||||
mContext.getContentResolver().unregisterContentObserver(
|
||||
mEnabledA11yServicesContentObserver);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.IntDef;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.PixelFormat;
|
||||
@@ -105,6 +106,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout
|
||||
private float mRadius;
|
||||
private float mPercentageY = LOCATION_Y_PERCENTAGE;
|
||||
private float mSquareScaledTouchSlop;
|
||||
private final Configuration mLastConfiguration;
|
||||
private final RecyclerView mListView;
|
||||
private final AccessibilityTargetAdapter mAdapter;
|
||||
private float mFadeOutValue;
|
||||
@@ -202,6 +204,8 @@ public class AccessibilityFloatingMenuView extends FrameLayout
|
||||
}
|
||||
});
|
||||
|
||||
mLastConfiguration = new Configuration(getResources().getConfiguration());
|
||||
|
||||
updateDimensions();
|
||||
initListView();
|
||||
updateStrokeWith(getResources().getConfiguration().uiMode, mAlignment);
|
||||
@@ -368,7 +372,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout
|
||||
|
||||
mTargets.clear();
|
||||
mTargets.addAll(newTargets);
|
||||
mAdapter.notifyDataSetChanged();
|
||||
onEnabledFeaturesChanged();
|
||||
|
||||
updateRadiusWith(mSizeType, mRadiusType, mTargets.size());
|
||||
updateScrollModeWith(hasExceededMaxLayoutHeight());
|
||||
@@ -416,6 +420,10 @@ public class AccessibilityFloatingMenuView extends FrameLayout
|
||||
setAlpha(mIsFadeEffectEnabled ? mFadeOutValue : /* completely opaque */ 1.0f);
|
||||
}
|
||||
|
||||
void onEnabledFeaturesChanged() {
|
||||
mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void fadeIn() {
|
||||
if (!mIsFadeEffectEnabled) {
|
||||
@@ -601,13 +609,17 @@ public class AccessibilityFloatingMenuView extends FrameLayout
|
||||
params.gravity = Gravity.START | Gravity.TOP;
|
||||
params.x = getMaxWindowX();
|
||||
params.y = (int) (getMaxWindowY() * mPercentageY);
|
||||
|
||||
updateAccessibilityTitle(params);
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
final int diff = newConfig.diff(mLastConfiguration);
|
||||
if ((diff & ActivityInfo.CONFIG_LOCALE) != 0) {
|
||||
updateAccessibilityTitle(mCurrentLayoutParams);
|
||||
}
|
||||
|
||||
updateDimensions();
|
||||
updateListView();
|
||||
@@ -616,6 +628,8 @@ public class AccessibilityFloatingMenuView extends FrameLayout
|
||||
updateStrokeWith(newConfig.uiMode, mAlignment);
|
||||
updateLocationWith(mAlignment, mPercentageY);
|
||||
updateScrollModeWith(hasExceededMaxLayoutHeight());
|
||||
|
||||
mLastConfiguration.setTo(newConfig);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -724,6 +738,11 @@ public class AccessibilityFloatingMenuView extends FrameLayout
|
||||
setInset(insetLeft, insetRight);
|
||||
}
|
||||
|
||||
private void updateAccessibilityTitle(WindowManager.LayoutParams params) {
|
||||
params.accessibilityTitle = getResources().getString(
|
||||
com.android.internal.R.string.accessibility_select_shortcut_menu_title);
|
||||
}
|
||||
|
||||
private void setInset(int left, int right) {
|
||||
final LayerDrawable layerDrawable = getMenuLayerDrawable();
|
||||
if (layerDrawable.getLayerInsetLeft(INDEX_MENU_ITEM) == left
|
||||
|
||||
@@ -24,9 +24,12 @@ import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.Adapter;
|
||||
|
||||
import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
|
||||
import com.android.internal.accessibility.dialog.AccessibilityTarget;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.accessibility.floatingmenu.AccessibilityTargetAdapter.ViewHolder;
|
||||
@@ -78,9 +81,20 @@ public class AccessibilityTargetAdapter extends Adapter<ViewHolder> {
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
holder.mIconView.setBackground(mTargets.get(position).getIcon());
|
||||
final AccessibilityTarget target = mTargets.get(position);
|
||||
holder.mIconView.setBackground(target.getIcon());
|
||||
holder.updateIconWidthHeight(mIconWidthHeight);
|
||||
holder.itemView.setOnClickListener((v) -> mTargets.get(position).onSelected());
|
||||
holder.itemView.setOnClickListener((v) -> target.onSelected());
|
||||
holder.itemView.setStateDescription(target.getStateDescription());
|
||||
holder.itemView.setContentDescription(target.getLabel());
|
||||
|
||||
final String clickHint = target.getFragmentType() == AccessibilityFragmentType.TOGGLE
|
||||
? holder.itemView.getResources().getString(
|
||||
R.string.accessibility_floating_button_action_double_tap_to_toggle)
|
||||
: null;
|
||||
ViewCompat.replaceAccessibilityAction(holder.itemView,
|
||||
AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
|
||||
clickHint, /* command= */ null);
|
||||
}
|
||||
|
||||
@ItemType
|
||||
|
||||
@@ -65,9 +65,9 @@ public class AccessibilityTargetAdapterTest extends SysuiTestCase {
|
||||
mTargets.add(mAccessibilityTarget);
|
||||
mAdapter = new AccessibilityTargetAdapter(mTargets);
|
||||
|
||||
final View root = LayoutInflater.from(mContext).inflate(
|
||||
final View rootView = LayoutInflater.from(mContext).inflate(
|
||||
R.layout.accessibility_floating_menu_item, null);
|
||||
mViewHolder = new ViewHolder(root);
|
||||
mViewHolder = new ViewHolder(rootView);
|
||||
when(mAccessibilityTarget.getIcon()).thenReturn(mIcon);
|
||||
when(mIcon.getConstantState()).thenReturn(mConstantState);
|
||||
}
|
||||
@@ -82,4 +82,27 @@ public class AccessibilityTargetAdapterTest extends SysuiTestCase {
|
||||
|
||||
assertThat(actualIconWith).isEqualTo(iconWidthHeight);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getContentDescription_invisibleToggleTarget_descriptionWithoutState() {
|
||||
when(mAccessibilityTarget.getFragmentType()).thenReturn(/* InvisibleToggle */ 1);
|
||||
when(mAccessibilityTarget.getLabel()).thenReturn("testLabel");
|
||||
when(mAccessibilityTarget.getStateDescription()).thenReturn("testState");
|
||||
|
||||
mAdapter.onBindViewHolder(mViewHolder, 0);
|
||||
|
||||
assertThat(mViewHolder.itemView.getContentDescription().toString().contentEquals(
|
||||
"testLabel")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getStateDescription_toggleTarget_switchOff_stateOffText() {
|
||||
when(mAccessibilityTarget.getFragmentType()).thenReturn(/* Toggle */ 2);
|
||||
when(mAccessibilityTarget.getStateDescription()).thenReturn("testState");
|
||||
|
||||
mAdapter.onBindViewHolder(mViewHolder, 0);
|
||||
|
||||
assertThat(mViewHolder.itemView.getStateDescription().toString().contentEquals(
|
||||
"testState")).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user