1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.accessibility; 18 19 import static android.content.Context.MODE_PRIVATE; 20 21 import static com.android.settings.accessibility.AutoclickUtils.AUTOCLICK_DELAY_STEP; 22 import static com.android.settings.accessibility.AutoclickUtils.KEY_CUSTOM_DELAY_VALUE; 23 import static com.android.settings.accessibility.AutoclickUtils.KEY_DELAY_MODE; 24 import static com.android.settings.accessibility.AutoclickUtils.MAX_AUTOCLICK_DELAY_MS; 25 import static com.android.settings.accessibility.AutoclickUtils.MIN_AUTOCLICK_DELAY_MS; 26 27 import android.content.ContentResolver; 28 import android.content.Context; 29 import android.content.SharedPreferences; 30 import android.provider.Settings; 31 import android.view.accessibility.AccessibilityManager; 32 import android.widget.ImageView; 33 import android.widget.SeekBar; 34 import android.widget.TextView; 35 36 import androidx.annotation.VisibleForTesting; 37 import androidx.preference.PreferenceScreen; 38 39 import com.android.settings.R; 40 import com.android.settings.core.BasePreferenceController; 41 import com.android.settingslib.core.lifecycle.LifecycleObserver; 42 import com.android.settingslib.core.lifecycle.events.OnStart; 43 import com.android.settingslib.core.lifecycle.events.OnStop; 44 import com.android.settingslib.widget.LayoutPreference; 45 46 /** Controller class that controls accessibility autoclick seekbar settings. */ 47 public class ToggleAutoclickCustomSeekbarController extends BasePreferenceController 48 implements LifecycleObserver, OnStart, OnStop, 49 SharedPreferences.OnSharedPreferenceChangeListener { 50 51 private final SharedPreferences mSharedPreferences; 52 private final ContentResolver mContentResolver; 53 private ImageView mShorter; 54 private ImageView mLonger; 55 private SeekBar mSeekBar; 56 private TextView mDelayLabel; 57 58 @VisibleForTesting 59 final SeekBar.OnSeekBarChangeListener mSeekBarChangeListener = 60 new SeekBar.OnSeekBarChangeListener() { 61 62 @Override 63 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 64 updateCustomDelayValue(seekBarProgressToDelay(progress)); 65 } 66 67 @Override 68 public void onStartTrackingTouch(SeekBar seekBar) { 69 // Nothing to do. 70 } 71 72 @Override 73 public void onStopTrackingTouch(SeekBar seekBar) { 74 // Nothing to do. 75 } 76 }; 77 ToggleAutoclickCustomSeekbarController(Context context, String preferenceKey)78 public ToggleAutoclickCustomSeekbarController(Context context, String preferenceKey) { 79 super(context, preferenceKey); 80 mSharedPreferences = context.getSharedPreferences(context.getPackageName(), MODE_PRIVATE); 81 mContentResolver = context.getContentResolver(); 82 } 83 84 @Override getAvailabilityStatus()85 public int getAvailabilityStatus() { 86 return AVAILABLE; 87 } 88 89 @Override onStart()90 public void onStart() { 91 if (mSharedPreferences != null) { 92 mSharedPreferences.registerOnSharedPreferenceChangeListener(this); 93 } 94 } 95 96 @Override onStop()97 public void onStop() { 98 if (mSharedPreferences != null) { 99 mSharedPreferences.unregisterOnSharedPreferenceChangeListener(this); 100 } 101 } 102 103 @Override displayPreference(PreferenceScreen screen)104 public void displayPreference(PreferenceScreen screen) { 105 super.displayPreference(screen); 106 final LayoutPreference preference = screen.findPreference(getPreferenceKey()); 107 108 if (isAvailable()) { 109 final int delayMillis = getSharedPreferenceForDelayValue(); 110 // Initialize seek bar preference. Sets seek bar size to the number of possible delay 111 // values. 112 mSeekBar = preference.findViewById(R.id.autoclick_delay); 113 mSeekBar.setMax(delayToSeekBarProgress(MAX_AUTOCLICK_DELAY_MS)); 114 mSeekBar.setProgress(delayToSeekBarProgress(delayMillis)); 115 mSeekBar.setOnSeekBarChangeListener(mSeekBarChangeListener); 116 117 mDelayLabel = preference.findViewById(R.id.current_label); 118 mDelayLabel.setText(delayTimeToString(delayMillis)); 119 120 mShorter = preference.findViewById(R.id.shorter); 121 mShorter.setOnClickListener(v -> minusDelayByImageView()); 122 123 mLonger = preference.findViewById(R.id.longer); 124 mLonger.setOnClickListener(v -> plusDelayByImageView()); 125 } 126 } 127 128 @Override onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)129 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { 130 if (KEY_DELAY_MODE.equals(key)) { 131 final int delayMillis = getSharedPreferenceForDelayValue(); 132 updateCustomDelayValue(delayMillis); 133 } 134 } 135 136 /** Converts seek bar preference progress value to autoclick delay associated with it. */ seekBarProgressToDelay(int progress)137 private int seekBarProgressToDelay(int progress) { 138 return progress * AUTOCLICK_DELAY_STEP + MIN_AUTOCLICK_DELAY_MS; 139 } 140 141 /** 142 * Converts autoclick delay value to seek bar preference progress values that represents said 143 * delay. 144 */ delayToSeekBarProgress(int delayMillis)145 private int delayToSeekBarProgress(int delayMillis) { 146 return (delayMillis - MIN_AUTOCLICK_DELAY_MS) / AUTOCLICK_DELAY_STEP; 147 } 148 getSharedPreferenceForDelayValue()149 private int getSharedPreferenceForDelayValue() { 150 final int delayMillis = Settings.Secure.getInt(mContentResolver, 151 Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY, 152 AccessibilityManager.AUTOCLICK_DELAY_DEFAULT); 153 154 return mSharedPreferences.getInt(KEY_CUSTOM_DELAY_VALUE, delayMillis); 155 } 156 updateCustomDelayValue(int delayMillis)157 private void updateCustomDelayValue(int delayMillis) { 158 Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY, 159 delayMillis); 160 mSharedPreferences.edit().putInt(KEY_CUSTOM_DELAY_VALUE, delayMillis).apply(); 161 mSeekBar.setProgress(delayToSeekBarProgress(delayMillis)); 162 mDelayLabel.setText(delayTimeToString(delayMillis)); 163 } 164 minusDelayByImageView()165 private void minusDelayByImageView() { 166 final int delayMillis = getSharedPreferenceForDelayValue(); 167 if (delayMillis > MIN_AUTOCLICK_DELAY_MS) { 168 updateCustomDelayValue(delayMillis - AUTOCLICK_DELAY_STEP); 169 } 170 } 171 plusDelayByImageView()172 private void plusDelayByImageView() { 173 final int delayMillis = getSharedPreferenceForDelayValue(); 174 if (delayMillis < MAX_AUTOCLICK_DELAY_MS) { 175 updateCustomDelayValue(delayMillis + AUTOCLICK_DELAY_STEP); 176 } 177 } delayTimeToString(int delayMillis)178 private CharSequence delayTimeToString(int delayMillis) { 179 return AutoclickUtils.getAutoclickDelaySummary(mContext, 180 R.string.accessibilty_autoclick_delay_unit_second, delayMillis); 181 } 182 } 183