diff options
8 files changed, 103 insertions, 11 deletions
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java index d84175ed1e7c..5b0abd389e7d 100644 --- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java +++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java @@ -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; } diff --git a/core/java/com/android/internal/accessibility/dialog/ToggleAccessibilityServiceTarget.java b/core/java/com/android/internal/accessibility/dialog/ToggleAccessibilityServiceTarget.java index 239e531dbfb8..469d10ff98aa 100644 --- a/core/java/com/android/internal/accessibility/dialog/ToggleAccessibilityServiceTarget.java +++ b/core/java/com/android/internal/accessibility/dialog/ToggleAccessibilityServiceTarget.java @@ -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); } } diff --git a/core/java/com/android/internal/accessibility/dialog/ToggleAllowListingFeatureTarget.java b/core/java/com/android/internal/accessibility/dialog/ToggleAllowListingFeatureTarget.java index 38aac708de15..ebdaed6dbe39 100644 --- a/core/java/com/android/internal/accessibility/dialog/ToggleAllowListingFeatureTarget.java +++ b/core/java/com/android/internal/accessibility/dialog/ToggleAllowListingFeatureTarget.java @@ -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() { diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index c117069f794b..e7d886d1c550 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2727,6 +2727,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=30]--> <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] --> diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java index 7b4ce61d2cfe..3b3bad3b255f 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java @@ -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); } } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java index 5502a20ce398..934e20dfbd05 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java @@ -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 diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapter.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapter.java index fd0c4ef0a5be..76106e7c2cf1 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapter.java @@ -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 diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapterTest.java index 899625eee7d9..afd5f77f7a4c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapterTest.java @@ -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(); + } } |