From 62aab02fc5567f992b6b064b7762d44d88b9ae21 Mon Sep 17 00:00:00 2001 From: ChenJean Date: Wed, 5 Feb 2020 19:08:38 +0800 Subject: [PATCH] Support autoclick secondary action (2/n) Add LayoutPreference to support new seekbar design. Bug: 146019277 Test: manual Change-Id: I8bfe3ca1ccee833fb941076ff33e7536392b90f4 --- ...accessibility_autoclick_custom_seekbar.xml | 69 ++++++ res/values/strings.xml | 12 +- res/xml/accessibility_autoclick_settings.xml | 10 +- ...oggleAutoclickCustomSeekbarController.java | 230 ++++++++++++++++++ .../ToggleAutoclickPreferenceController.java | 78 +----- .../ToggleAutoclickPreferenceFragment.java | 4 +- 6 files changed, 328 insertions(+), 75 deletions(-) create mode 100644 res/layout/accessibility_autoclick_custom_seekbar.xml create mode 100644 src/com/android/settings/accessibility/ToggleAutoclickCustomSeekbarController.java diff --git a/res/layout/accessibility_autoclick_custom_seekbar.xml b/res/layout/accessibility_autoclick_custom_seekbar.xml new file mode 100644 index 00000000000..74837592671 --- /dev/null +++ b/res/layout/accessibility_autoclick_custom_seekbar.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 0ddc62a4279..d0c283918db 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4936,7 +4936,7 @@ If you are using a mouse, you can set the cursor to take action automatically when it stops moving for a certain amount of time. - None + Don\u2019t use auto click (default) Short @@ -4951,6 +4951,10 @@ 1 second Custom + + Shorter + + Longer Vibration & haptic strength @@ -5052,6 +5056,12 @@ Very long delay (%1$d ms) + + + %1$s second + %1$s seconds + + Ring %1$s, notification %2$s, touch %3$s diff --git a/res/xml/accessibility_autoclick_settings.xml b/res/xml/accessibility_autoclick_settings.xml index 70cb9c844ad..f157efd75ae 100644 --- a/res/xml/accessibility_autoclick_settings.xml +++ b/res/xml/accessibility_autoclick_settings.xml @@ -44,13 +44,17 @@ android:key="accessibility_control_autoclick_custom" android:title="@string/accessibility_autoclick_custom_title" /> - + + settings:searchable="false" /> diff --git a/src/com/android/settings/accessibility/ToggleAutoclickCustomSeekbarController.java b/src/com/android/settings/accessibility/ToggleAutoclickCustomSeekbarController.java new file mode 100644 index 00000000000..9079c319f59 --- /dev/null +++ b/src/com/android/settings/accessibility/ToggleAutoclickCustomSeekbarController.java @@ -0,0 +1,230 @@ +/* + * 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.settings.accessibility; + +import static android.content.Context.MODE_PRIVATE; + +import static com.android.settings.accessibility.ToggleAutoclickPreferenceController.KEY_DELAY_MODE; + +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.annotation.IntDef; +import android.content.ContentResolver; +import android.content.Context; +import android.content.SharedPreferences; +import android.provider.Settings; +import android.view.accessibility.AccessibilityManager; +import android.widget.ImageView; +import android.widget.SeekBar; +import android.widget.TextView; + +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnPause; +import com.android.settingslib.core.lifecycle.events.OnResume; +import com.android.settingslib.widget.LayoutPreference; + +import java.lang.annotation.Retention; + +/** + * Controller class that controls accessibility autoclick seekbar settings. + */ +public class ToggleAutoclickCustomSeekbarController extends BasePreferenceController + implements LifecycleObserver, OnResume, OnPause, + SharedPreferences.OnSharedPreferenceChangeListener { + + @Retention(SOURCE) + @IntDef({ + Quantity.OTHER, + Quantity.ONE + }) + @interface Quantity { + int OTHER = 0; + int ONE = 1; + } + + private static final String CONTROL_AUTOCLICK_DELAY_SECURE = + Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY; + private static final String KEY_CUSTOM_DELAY_VALUE = "custom_delay_value"; + + // Min allowed autoclick delay value. + static final int MIN_AUTOCLICK_DELAY_MS = 200; + + // Max allowed autoclick delay value. + static final int MAX_AUTOCLICK_DELAY_MS = 1000; + + // Allowed autoclick delay values are discrete. + // This is the difference between two allowed values. + private static final int AUTOCLICK_DELAY_STEP = 100; + + private final SharedPreferences mSharedPreferences; + private final ContentResolver mContentResolver; + private ImageView mShorter; + private ImageView mLonger; + private SeekBar mSeekBar; + private TextView mDelayLabel; + + private final SeekBar.OnSeekBarChangeListener mSeekBarChangeListener = + new SeekBar.OnSeekBarChangeListener() { + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + updateCustomDelayValue(seekBarProgressToDelay(progress)); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + // Nothing to do. + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + // Nothing to do. + } + }; + + public ToggleAutoclickCustomSeekbarController(Context context, String preferenceKey) { + super(context, preferenceKey); + mSharedPreferences = context.getSharedPreferences(context.getPackageName(), MODE_PRIVATE); + mContentResolver = context.getContentResolver(); + } + + public ToggleAutoclickCustomSeekbarController(Context context, Lifecycle lifecycle, + String preferenceKey) { + this(context, preferenceKey); + + if (lifecycle != null) { + lifecycle.addObserver(this); + } + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } + + @Override + public void onResume() { + if (mSharedPreferences != null) { + mSharedPreferences.registerOnSharedPreferenceChangeListener(this); + } + } + + @Override + public void onPause() { + if (mSharedPreferences != null) { + mSharedPreferences.unregisterOnSharedPreferenceChangeListener(this); + } + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + final LayoutPreference preference = screen.findPreference(getPreferenceKey()); + + if (isAvailable()) { + int delayMillis = getSharedPreferenceForDelayValue(); + // Initialize seek bar preference. Sets seek bar size to the number of possible delay + // values. + mSeekBar = preference.findViewById(R.id.autoclick_delay); + mSeekBar.setMax(delayToSeekBarProgress(MAX_AUTOCLICK_DELAY_MS)); + mSeekBar.setProgress(delayToSeekBarProgress(delayMillis)); + mSeekBar.setOnSeekBarChangeListener(mSeekBarChangeListener); + + mDelayLabel = preference.findViewById(R.id.current_label); + mDelayLabel.setText(delayTimeToString(delayMillis)); + + mShorter = preference.findViewById(R.id.smaller); + mShorter.setOnClickListener(v -> { + minusDelayByImageView(); + }); + + mLonger = preference.findViewById(R.id.larger); + mLonger.setOnClickListener(v -> { + plusDelayByImageView(); + }); + } + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (KEY_DELAY_MODE.equals(key)) { + int delayMillis = getSharedPreferenceForDelayValue(); + updateCustomDelayValue(delayMillis); + } + } + + /** Converts seek bar preference progress value to autoclick delay associated with it. */ + private int seekBarProgressToDelay(int progress) { + return progress * AUTOCLICK_DELAY_STEP + MIN_AUTOCLICK_DELAY_MS; + } + + /** + * Converts autoclick delay value to seek bar preference progress values that represents said + * delay. + */ + private int delayToSeekBarProgress(int delayMillis) { + return (delayMillis - MIN_AUTOCLICK_DELAY_MS) / AUTOCLICK_DELAY_STEP; + } + + private int getSharedPreferenceForDelayValue() { + int delayMillis = mSharedPreferences.getInt(KEY_CUSTOM_DELAY_VALUE, + AccessibilityManager.AUTOCLICK_DELAY_DEFAULT); + + return delayMillis; + } + + private void putSecureInt(String name, int value) { + Settings.Secure.putInt(mContentResolver, name, value); + } + + private void updateCustomDelayValue(int delayMillis) { + putSecureInt(CONTROL_AUTOCLICK_DELAY_SECURE, delayMillis); + mSharedPreferences.edit().putInt(KEY_CUSTOM_DELAY_VALUE, delayMillis).apply(); + mSeekBar.setProgress(delayToSeekBarProgress(delayMillis)); + mDelayLabel.setText(delayTimeToString(delayMillis)); + } + + private void minusDelayByImageView() { + int delayMillis = getSharedPreferenceForDelayValue(); + if (delayMillis > MIN_AUTOCLICK_DELAY_MS) { + updateCustomDelayValue(delayMillis - AUTOCLICK_DELAY_STEP); + } + } + + private void plusDelayByImageView() { + int delayMillis = getSharedPreferenceForDelayValue(); + if (delayMillis < MAX_AUTOCLICK_DELAY_MS) { + updateCustomDelayValue(delayMillis + AUTOCLICK_DELAY_STEP); + } + } + + private CharSequence delayTimeToString(int delayMillis) { + final int quantity = (delayMillis == 1000) ? Quantity.ONE : Quantity.OTHER; + final float delaySecond = (float) delayMillis / 1000; + // Only show integer when delay time is 1. + final String decimalFormat = (delaySecond == 1) ? "%.0f" : "%.1f"; + + return mContext.getResources().getQuantityString( + R.plurals.accessibilty_autoclick_delay_unit_second, + quantity, String.format(decimalFormat, delaySecond)); + } +} diff --git a/src/com/android/settings/accessibility/ToggleAutoclickPreferenceController.java b/src/com/android/settings/accessibility/ToggleAutoclickPreferenceController.java index 33ebfc582d1..45cdf913fe0 100644 --- a/src/com/android/settings/accessibility/ToggleAutoclickPreferenceController.java +++ b/src/com/android/settings/accessibility/ToggleAutoclickPreferenceController.java @@ -24,7 +24,6 @@ import android.content.SharedPreferences; import android.content.res.Resources; import android.provider.Settings; import android.util.ArrayMap; -import android.view.accessibility.AccessibilityManager; import androidx.lifecycle.LifecycleObserver; import androidx.preference.Preference; @@ -33,8 +32,8 @@ import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.PreferenceControllerMixin; -import com.android.settings.widget.SeekBarPreference; import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.widget.LayoutPreference; import com.android.settingslib.widget.RadioButtonPreference; import java.util.Map; @@ -43,23 +42,13 @@ import java.util.Map; * Controller class that controls accessibility autoclick settings. */ public class ToggleAutoclickPreferenceController extends BasePreferenceController implements - LifecycleObserver, RadioButtonPreference.OnClickListener, PreferenceControllerMixin, - Preference.OnPreferenceChangeListener { - // Min allowed autoclick delay value. - static final int MIN_AUTOCLICK_DELAY_MS = 200; - - // Max allowed autoclick delay value. - static final int MAX_AUTOCLICK_DELAY_MS = 1000; + LifecycleObserver, RadioButtonPreference.OnClickListener, PreferenceControllerMixin { private static final String CONTROL_AUTOCLICK_DELAY_SECURE = Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY; - private static final String KEY_AUTOCLICK_DELA = "autoclick_delay"; - private static final String KEY_CUSTOM_DELAY_VALUE = "custom_delay_value"; - private static final String KEY_DELAY_MODE = "delay_mode"; + private static final String KEY_AUTOCLICK_CUSTOM_SEEKBAR = "autoclick_custom_seekbar"; + static final String KEY_DELAY_MODE = "delay_mode"; - // Allowed autoclick delay values are discrete. - // This is the difference between two allowed values. - private static final int AUTOCLICK_DELAY_STEP = 100; private static final int AUTOCLICK_OFF_MODE = 0; private static final int AUTOCLICK_CUSTOM_MODE = 2000; @@ -77,7 +66,7 @@ public class ToggleAutoclickPreferenceController extends BasePreferenceControlle * number of possible discrete autoclick delay values. These will have to be converted to actual * delay values before saving them in settings. */ - private SeekBarPreference mCustomDelayPref; + private LayoutPreference mSeekBerPreference; private int mCurrentUiAutoClickMode; public ToggleAutoclickPreferenceController(Context context, String preferenceKey) { @@ -121,16 +110,7 @@ public class ToggleAutoclickPreferenceController extends BasePreferenceControlle mDelayModePref = (RadioButtonPreference) screen.findPreference(getPreferenceKey()); mDelayModePref.setOnClickListener(this); - - int delay = getSharedPreferenceForDelayValue(); - - // Initialize seek bar preference. Sets seek bar size to the number of possible delay - // values. - mCustomDelayPref = (SeekBarPreference) screen.findPreference(KEY_AUTOCLICK_DELA); - mCustomDelayPref.setMax(delayToSeekBarProgress(MAX_AUTOCLICK_DELAY_MS)); - mCustomDelayPref.setProgress(delayToSeekBarProgress(delay)); - mCustomDelayPref.setOnPreferenceChangeListener(this); - + mSeekBerPreference = (LayoutPreference) screen.findPreference(KEY_AUTOCLICK_CUSTOM_SEEKBAR); updateState((Preference) mDelayModePref); } @@ -150,14 +130,7 @@ public class ToggleAutoclickPreferenceController extends BasePreferenceControlle } private void updatePreferenceVisibleState(int mode) { - mCustomDelayPref.setVisible(mCurrentUiAutoClickMode == mode); - } - - private void updateSeekBarProgressState() { - if (mCurrentUiAutoClickMode == AUTOCLICK_CUSTOM_MODE) { - int delay = getSharedPreferenceForDelayValue(); - mCustomDelayPref.setProgress(delayToSeekBarProgress(delay)); - } + mSeekBerPreference.setVisible(mCurrentUiAutoClickMode == mode); } @Override @@ -169,22 +142,10 @@ public class ToggleAutoclickPreferenceController extends BasePreferenceControlle // Reset RadioButton. mDelayModePref.setChecked(false); int mode = mAccessibilityAutoclickKeyToValueMap.get(mDelayModePref.getKey()); - updateSeekBarProgressState(); updatePreferenceCheckedState(mode); updatePreferenceVisibleState(mode); } - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (preference == mCustomDelayPref && newValue instanceof Integer) { - putSecureInt(CONTROL_AUTOCLICK_DELAY_SECURE, seekBarProgressToDelay((int) newValue)); - mSharedPreferences.edit().putInt(KEY_CUSTOM_DELAY_VALUE, - seekBarProgressToDelay((int) newValue)).apply(); - return true; - } - return false; - } - /** Listener interface handles checked event. */ public interface OnChangeListener { /** @@ -216,37 +177,16 @@ public class ToggleAutoclickPreferenceController extends BasePreferenceControlle mSharedPreferences.edit().putInt(KEY_DELAY_MODE, preference).apply(); if (preference == AUTOCLICK_CUSTOM_MODE) { - putSecureInt(CONTROL_AUTOCLICK_DELAY_SECURE, getSharedPreferenceForDelayValue()); - } else { - putSecureInt(CONTROL_AUTOCLICK_DELAY_SECURE, preference); + return; } - } - /** Converts seek bar preference progress value to autoclick delay associated with it. */ - private int seekBarProgressToDelay(int progress) { - return progress * AUTOCLICK_DELAY_STEP + MIN_AUTOCLICK_DELAY_MS; - } - - /** - * Converts autoclick delay value to seek bar preference progress values that represents said - * delay. - */ - private int delayToSeekBarProgress(int delay) { - return (delay - MIN_AUTOCLICK_DELAY_MS) / AUTOCLICK_DELAY_STEP; + putSecureInt(CONTROL_AUTOCLICK_DELAY_SECURE, preference); } private void putSecureInt(String name, int value) { Settings.Secure.putInt(mContentResolver, name, value); } - private int getSharedPreferenceForDelayValue() { - int mode = mSharedPreferences.getInt(KEY_DELAY_MODE, AUTOCLICK_OFF_MODE); - int delay = mSharedPreferences.getInt(KEY_CUSTOM_DELAY_VALUE, - AccessibilityManager.AUTOCLICK_DELAY_DEFAULT); - - return mode == AUTOCLICK_CUSTOM_MODE ? delay : mode; - } - private int getSharedPreferenceForAutoClickMode() { return mSharedPreferences.getInt(KEY_DELAY_MODE, AUTOCLICK_OFF_MODE); } diff --git a/src/com/android/settings/accessibility/ToggleAutoclickPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAutoclickPreferenceFragment.java index 0ba54eb3a9f..4a88956a761 100644 --- a/src/com/android/settings/accessibility/ToggleAutoclickPreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleAutoclickPreferenceFragment.java @@ -16,8 +16,8 @@ package com.android.settings.accessibility; -import static com.android.settings.accessibility.ToggleAutoclickPreferenceController.MAX_AUTOCLICK_DELAY_MS; -import static com.android.settings.accessibility.ToggleAutoclickPreferenceController.MIN_AUTOCLICK_DELAY_MS; +import static com.android.settings.accessibility.ToggleAutoclickCustomSeekbarController.MAX_AUTOCLICK_DELAY_MS; +import static com.android.settings.accessibility.ToggleAutoclickCustomSeekbarController.MIN_AUTOCLICK_DELAY_MS; import android.app.settings.SettingsEnums; import android.content.Context;