Update accesibility button to suuport accessibility gesutre
1. Add gesture preference controller for gesture navigation 2. Auto update the preview illustarion when screen reader is on 3. Auto update accessibility button title for system navigation Bug: 190563948 Test: make RunSettingsRoboTests ROBOTEST_FILTER=AccessibilityButtonGesturePreferenceControllerTest ROBOTEST_FILTER=AccessibilityButtonPreviewPreferenceControllerTest ROBOTEST_FILTER=AccessibilityLayerDrawableTest ROBOTEST_FILTER=AccessibilityPreferenceControllerTest ROBOTEST_FILTER=AccessibilityButtonFooterPreferenceControllerTest Change-Id: Ifa98fc029430d86d3143133b3203b239340f2e41
This commit is contained in:
@@ -47,13 +47,12 @@ public class AccessibilityButtonFooterPreferenceController extends
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
// Need to update footerPreference's data before super.displayPreference(), then it will use
|
||||
// data to update related property of footerPreference.
|
||||
if (AccessibilityUtil.isGestureNavigateEnabled(mContext)) {
|
||||
final AccessibilityFooterPreference footerPreference =
|
||||
screen.findPreference(getPreferenceKey());
|
||||
footerPreference.setTitle(
|
||||
mContext.getString(R.string.accessibility_button_gesture_description));
|
||||
}
|
||||
|
||||
final int titleResource = AccessibilityUtil.isGestureNavigateEnabled(mContext)
|
||||
? R.string.accessibility_button_gesture_description
|
||||
: R.string.accessibility_button_description;
|
||||
final AccessibilityFooterPreference footerPreference =
|
||||
screen.findPreference(getPreferenceKey());
|
||||
footerPreference.setTitle(titleResource);
|
||||
super.displayPreference(screen);
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
@@ -29,6 +30,14 @@ public class AccessibilityButtonFragment extends DashboardFragment {
|
||||
|
||||
private static final String TAG = "AccessibilityButtonFragment";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
final int titleResource = AccessibilityUtil.isGestureNavigateEnabled(getPrefContext())
|
||||
? R.string.accessibility_button_gesture_title : R.string.accessibility_button_title;
|
||||
getActivity().setTitle(titleResource);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.accessibility_button_settings;
|
||||
|
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.settings.accessibility;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
import com.google.common.primitives.Ints;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/** Preference controller that controls the button or gesture in accessibility button page. */
|
||||
public class AccessibilityButtonGesturePreferenceController extends BasePreferenceController
|
||||
implements Preference.OnPreferenceChangeListener {
|
||||
|
||||
private Optional<Integer> mDefaultGesture = Optional.empty();
|
||||
|
||||
public AccessibilityButtonGesturePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AccessibilityUtil.isGestureNavigateEnabled(mContext)
|
||||
? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
final ListPreference listPreference = (ListPreference) preference;
|
||||
final Integer value = Ints.tryParse((String) newValue);
|
||||
if (value != null) {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, value);
|
||||
updateState(listPreference);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
super.updateState(preference);
|
||||
final ListPreference listPreference = (ListPreference) preference;
|
||||
|
||||
listPreference.setValue(getCurrentAccessibilityButtonMode());
|
||||
}
|
||||
|
||||
private String getCurrentAccessibilityButtonMode() {
|
||||
final int mode = Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, getDefaultGestureValue());
|
||||
return String.valueOf(mode);
|
||||
}
|
||||
|
||||
private int getDefaultGestureValue() {
|
||||
if (!mDefaultGesture.isPresent()) {
|
||||
final String[] valuesList = mContext.getResources().getStringArray(
|
||||
R.array.accessibility_button_gesture_selector_values);
|
||||
mDefaultGesture = Optional.of(Integer.parseInt(valuesList[0]));
|
||||
}
|
||||
return mDefaultGesture.get();
|
||||
}
|
||||
}
|
@@ -18,7 +18,6 @@ package com.android.settings.accessibility;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
@@ -28,16 +27,16 @@ import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
import com.google.common.primitives.Ints;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/** Preference controller that controls the preferred location in accessibility button page. */
|
||||
public class AccessibilityButtonLocationPreferenceController extends BasePreferenceController
|
||||
implements Preference.OnPreferenceChangeListener {
|
||||
|
||||
private final ArrayMap<String, String> mValueTitleMap = new ArrayMap<>();
|
||||
private int mDefaultLocation;
|
||||
private Optional<Integer> mDefaultLocation = Optional.empty();
|
||||
|
||||
public AccessibilityButtonLocationPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
initValueTitleMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -68,22 +67,16 @@ public class AccessibilityButtonLocationPreferenceController extends BasePrefere
|
||||
|
||||
private String getCurrentAccessibilityButtonMode() {
|
||||
final int mode = Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, mDefaultLocation);
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, getDefaultLocationValue());
|
||||
return String.valueOf(mode);
|
||||
}
|
||||
|
||||
private void initValueTitleMap() {
|
||||
if (mValueTitleMap.size() == 0) {
|
||||
final String[] values = mContext.getResources().getStringArray(
|
||||
private int getDefaultLocationValue() {
|
||||
if (!mDefaultLocation.isPresent()) {
|
||||
final String[] valuesList = mContext.getResources().getStringArray(
|
||||
R.array.accessibility_button_location_selector_values);
|
||||
final String[] titles = mContext.getResources().getStringArray(
|
||||
R.array.accessibility_button_location_selector_titles);
|
||||
final int mapSize = values.length;
|
||||
|
||||
mDefaultLocation = Integer.parseInt(values[0]);
|
||||
for (int i = 0; i < mapSize; i++) {
|
||||
mValueTitleMap.put(values[i], titles[i]);
|
||||
}
|
||||
mDefaultLocation = Optional.of(Integer.parseInt(valuesList[0]));
|
||||
}
|
||||
return mDefaultLocation.get();
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.settings.accessibility;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
/**
|
||||
* Preference controller for accessibility button preference.
|
||||
*/
|
||||
public class AccessibilityButtonPreferenceController extends BasePreferenceController {
|
||||
|
||||
public AccessibilityButtonPreferenceController(Context context, String key) {
|
||||
super(context, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
final int titleResource = AccessibilityUtil.isGestureNavigateEnabled(mContext)
|
||||
? R.string.accessibility_button_gesture_title : R.string.accessibility_button_title;
|
||||
final Preference preference = screen.findPreference(getPreferenceKey());
|
||||
preference.setTitle(titleResource);
|
||||
|
||||
}
|
||||
}
|
@@ -23,6 +23,7 @@ import android.graphics.drawable.Drawable;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.provider.Settings;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
@@ -46,11 +47,14 @@ public class AccessibilityButtonPreviewPreferenceController extends BasePreferen
|
||||
private final ContentResolver mContentResolver;
|
||||
@VisibleForTesting
|
||||
final ContentObserver mContentObserver;
|
||||
private FloatingMenuLayerDrawable mFloatingMenuPreviewDrawable;
|
||||
private AccessibilityLayerDrawable mAccessibilityPreviewDrawable;
|
||||
|
||||
@VisibleForTesting
|
||||
ImageView mPreview;
|
||||
|
||||
private AccessibilityManager.TouchExplorationStateChangeListener
|
||||
mTouchExplorationStateChangeListener;
|
||||
|
||||
public AccessibilityButtonPreviewPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mContentResolver = context.getContentResolver();
|
||||
@@ -60,6 +64,9 @@ public class AccessibilityButtonPreviewPreferenceController extends BasePreferen
|
||||
updatePreviewPreference();
|
||||
}
|
||||
};
|
||||
mTouchExplorationStateChangeListener = isTouchExplorationEnabled -> {
|
||||
updatePreviewPreference();
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -78,6 +85,9 @@ public class AccessibilityButtonPreviewPreferenceController extends BasePreferen
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
final AccessibilityManager am = mContext.getSystemService(AccessibilityManager.class);
|
||||
am.addTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener);
|
||||
|
||||
mContentResolver.registerContentObserver(
|
||||
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_MODE),
|
||||
/* notifyForDescendants= */ false, mContentObserver);
|
||||
@@ -91,6 +101,9 @@ public class AccessibilityButtonPreviewPreferenceController extends BasePreferen
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
final AccessibilityManager am = mContext.getSystemService(AccessibilityManager.class);
|
||||
am.removeTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener);
|
||||
|
||||
mContentResolver.unregisterContentObserver(mContentObserver);
|
||||
}
|
||||
|
||||
@@ -103,9 +116,14 @@ public class AccessibilityButtonPreviewPreferenceController extends BasePreferen
|
||||
final int floatingMenuIconId = (size == SMALL_SIZE)
|
||||
? R.drawable.accessibility_button_preview_small_floating_menu
|
||||
: R.drawable.accessibility_button_preview_large_floating_menu;
|
||||
|
||||
mPreview.setImageDrawable(getFloatingMenuPreviewDrawable(floatingMenuIconId, opacity));
|
||||
// Only change opacity(alpha) would not invoke redraw view, need to invalidate manually.
|
||||
mPreview.setImageDrawable(getAccessibilityPreviewDrawable(floatingMenuIconId, opacity));
|
||||
mPreview.invalidate();
|
||||
} else if (AccessibilityUtil.isGestureNavigateEnabled(mContext)) {
|
||||
// TODO(b/193081959): Use static illustartion instead.
|
||||
final int resId = AccessibilityUtil.isTouchExploreEnabled(mContext)
|
||||
? R.drawable.accessibility_button_preview_three_finger
|
||||
: R.drawable.accessibility_button_preview_two_finger;
|
||||
mPreview.setImageDrawable(getAccessibilityPreviewDrawable(resId, /* opacity= */ 100));
|
||||
mPreview.invalidate();
|
||||
} else {
|
||||
mPreview.setImageDrawable(
|
||||
@@ -113,14 +131,14 @@ public class AccessibilityButtonPreviewPreferenceController extends BasePreferen
|
||||
}
|
||||
}
|
||||
|
||||
private Drawable getFloatingMenuPreviewDrawable(int resId, int opacity) {
|
||||
if (mFloatingMenuPreviewDrawable == null) {
|
||||
mFloatingMenuPreviewDrawable = FloatingMenuLayerDrawable.createLayerDrawable(
|
||||
private Drawable getAccessibilityPreviewDrawable(int resId, int opacity) {
|
||||
if (mAccessibilityPreviewDrawable == null) {
|
||||
mAccessibilityPreviewDrawable = AccessibilityLayerDrawable.createLayerDrawable(
|
||||
mContext, resId, opacity);
|
||||
} else {
|
||||
mFloatingMenuPreviewDrawable.updateLayerDrawable(mContext, resId, opacity);
|
||||
mAccessibilityPreviewDrawable.updateLayerDrawable(mContext, resId, opacity);
|
||||
}
|
||||
|
||||
return mFloatingMenuPreviewDrawable;
|
||||
return mAccessibilityPreviewDrawable;
|
||||
}
|
||||
}
|
||||
|
@@ -27,10 +27,10 @@ import com.android.settings.R;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/** LayerDrawable that contains device icon as background and floating menu icon as foreground. */
|
||||
public class FloatingMenuLayerDrawable extends LayerDrawable {
|
||||
/** LayerDrawable that contains device icon as background and given icon as foreground. */
|
||||
public class AccessibilityLayerDrawable extends LayerDrawable {
|
||||
|
||||
private FloatingMenuLayerDrawableState mState;
|
||||
private AccessibilityLayerDrawableState mState;
|
||||
|
||||
/**
|
||||
* Creates a new layer drawable with the list of specified layers.
|
||||
@@ -38,23 +38,23 @@ public class FloatingMenuLayerDrawable extends LayerDrawable {
|
||||
* @param layers a list of drawables to use as layers in this new drawable,
|
||||
* must be non-null
|
||||
*/
|
||||
private FloatingMenuLayerDrawable(@NonNull Drawable[] layers) {
|
||||
private AccessibilityLayerDrawable(@NonNull Drawable[] layers) {
|
||||
super(layers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the {@link LayerDrawable} that contains device icon as background and floating menu
|
||||
* icon with given {@code opacity} value as foreground.
|
||||
* Create the {@link LayerDrawable} that contains device icon as background and given menu icon
|
||||
* with given {@code opacity} value as foreground.
|
||||
*
|
||||
* @param context the valid context used to get the icon
|
||||
* @param resId the resource ID of the floating menu icon
|
||||
* @param resId the resource ID of the given icon
|
||||
* @param opacity the opacity to apply to the given icon
|
||||
* @return the drawable that combines the device icon and the floating menu icon
|
||||
* @return the drawable that combines the device icon and the given icon
|
||||
*/
|
||||
public static FloatingMenuLayerDrawable createLayerDrawable(Context context, int resId,
|
||||
public static AccessibilityLayerDrawable createLayerDrawable(Context context, int resId,
|
||||
int opacity) {
|
||||
final Drawable bg = context.getDrawable(R.drawable.accessibility_button_preview_base);
|
||||
final FloatingMenuLayerDrawable basicDrawable = new FloatingMenuLayerDrawable(
|
||||
final AccessibilityLayerDrawable basicDrawable = new AccessibilityLayerDrawable(
|
||||
new Drawable[]{bg, null});
|
||||
|
||||
basicDrawable.updateLayerDrawable(context, resId, opacity);
|
||||
@@ -66,7 +66,7 @@ public class FloatingMenuLayerDrawable extends LayerDrawable {
|
||||
* value at index 1 layer.
|
||||
*
|
||||
* @param context the valid context used to get the icon
|
||||
* @param resId the resource ID of the floating menu icon
|
||||
* @param resId the resource ID of the given icon
|
||||
* @param opacity the opacity to apply to the given icon
|
||||
*/
|
||||
public void updateLayerDrawable(Context context, int resId, int opacity) {
|
||||
@@ -83,18 +83,18 @@ public class FloatingMenuLayerDrawable extends LayerDrawable {
|
||||
|
||||
/** Stores the constant state and data to the given drawable. */
|
||||
private void setConstantState(Context context, int resId, int opacity) {
|
||||
mState = new FloatingMenuLayerDrawableState(context, resId, opacity);
|
||||
mState = new AccessibilityLayerDrawableState(context, resId, opacity);
|
||||
}
|
||||
|
||||
/** {@link ConstantState} to store the data of {@link FloatingMenuLayerDrawable}. */
|
||||
/** {@link ConstantState} to store the data of {@link AccessibilityLayerDrawable}. */
|
||||
@VisibleForTesting
|
||||
static class FloatingMenuLayerDrawableState extends ConstantState {
|
||||
static class AccessibilityLayerDrawableState extends ConstantState {
|
||||
|
||||
private final Context mContext;
|
||||
private final int mResId;
|
||||
private final int mOpacity;
|
||||
|
||||
FloatingMenuLayerDrawableState(Context context, int resId, int opacity) {
|
||||
AccessibilityLayerDrawableState(Context context, int resId, int opacity) {
|
||||
mContext = context;
|
||||
mResId = resId;
|
||||
mOpacity = opacity;
|
||||
@@ -119,7 +119,7 @@ public class FloatingMenuLayerDrawable extends LayerDrawable {
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final FloatingMenuLayerDrawableState that = (FloatingMenuLayerDrawableState) o;
|
||||
final AccessibilityLayerDrawableState that = (AccessibilityLayerDrawableState) o;
|
||||
return mResId == that.mResId
|
||||
&& mOpacity == that.mOpacity
|
||||
&& Objects.equals(mContext, that.mContext);
|
Reference in New Issue
Block a user