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