1 /*
2  * Copyright (C) 2018 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 android.content.ContentResolver;
20 import android.content.Context;
21 import android.content.res.Resources;
22 import android.provider.Settings;
23 
24 import androidx.lifecycle.LifecycleObserver;
25 import androidx.preference.Preference;
26 import androidx.preference.PreferenceScreen;
27 
28 import com.android.settings.R;
29 import com.android.settings.core.PreferenceControllerMixin;
30 import com.android.settingslib.core.AbstractPreferenceController;
31 import com.android.settingslib.core.lifecycle.Lifecycle;
32 import com.android.settingslib.widget.RadioButtonPreference;
33 
34 import com.google.common.primitives.Ints;
35 
36 import java.util.HashMap;
37 import java.util.Map;
38 
39 /**
40  * Controller class that control accessibility time out settings.
41  */
42 public class AccessibilityTimeoutController extends AbstractPreferenceController implements
43         LifecycleObserver, RadioButtonPreference.OnClickListener, PreferenceControllerMixin {
44     static final String CONTENT_TIMEOUT_SETTINGS_SECURE =
45             Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS;
46     static final String CONTROL_TIMEOUT_SETTINGS_SECURE =
47             Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS;
48 
49     // pair the preference key and timeout value.
50     private final Map<String, Integer> mAccessibilityTimeoutKeyToValueMap = new HashMap<>();
51 
52     // RadioButtonPreference key, each preference represent a timeout value.
53     private final String mPreferenceKey;
54     private final ContentResolver mContentResolver;
55     private final Resources mResources;
56     private OnChangeListener mOnChangeListener;
57     private RadioButtonPreference mPreference;
58     private int mAccessibilityUiTimeoutValue;
59 
AccessibilityTimeoutController(Context context, Lifecycle lifecycle, String preferenceKey)60     public AccessibilityTimeoutController(Context context, Lifecycle lifecycle,
61             String preferenceKey) {
62         super(context);
63 
64         mContentResolver = context.getContentResolver();
65         mResources = context.getResources();
66 
67         if (lifecycle != null) {
68             lifecycle.addObserver(this);
69         }
70         mPreferenceKey = preferenceKey;
71     }
72 
getSecureAccessibilityTimeoutValue(ContentResolver resolver, String name)73     protected static int getSecureAccessibilityTimeoutValue(ContentResolver resolver, String name) {
74         String timeOutSec = Settings.Secure.getString(resolver, name);
75         if (timeOutSec == null) {
76             return 0;
77         }
78         Integer timeOutValue = Ints.tryParse(timeOutSec);
79         return timeOutValue == null ? 0 : timeOutValue;
80     }
81 
setOnChangeListener(OnChangeListener listener)82     public void setOnChangeListener(OnChangeListener listener) {
83         mOnChangeListener = listener;
84     }
85 
getTimeoutValueToKeyMap()86     private Map<String, Integer> getTimeoutValueToKeyMap() {
87         if (mAccessibilityTimeoutKeyToValueMap.size() == 0) {
88 
89             String[] timeoutKeys = mResources.getStringArray(
90                     R.array.accessibility_timeout_control_selector_keys);
91 
92             int[] timeoutValues = mResources.getIntArray(
93                     R.array.accessibility_timeout_selector_values);
94 
95             final int timeoutValueCount = timeoutValues.length;
96             for (int i = 0; i < timeoutValueCount; i++) {
97                 mAccessibilityTimeoutKeyToValueMap.put(timeoutKeys[i], timeoutValues[i]);
98             }
99         }
100         return mAccessibilityTimeoutKeyToValueMap;
101     }
102 
putSecureString(String name, String value)103     private void putSecureString(String name, String value) {
104         Settings.Secure.putString(mContentResolver, name, value);
105     }
106 
handlePreferenceChange(String value)107     private void handlePreferenceChange(String value) {
108         // save value to both content and control timeout setting.
109         putSecureString(Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS, value);
110         putSecureString(Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, value);
111     }
112 
113     @Override
isAvailable()114     public boolean isAvailable() {
115         return true;
116     }
117 
118     @Override
getPreferenceKey()119     public String getPreferenceKey() {
120         return mPreferenceKey;
121     }
122 
123     @Override
displayPreference(PreferenceScreen screen)124     public void displayPreference(PreferenceScreen screen) {
125         super.displayPreference(screen);
126 
127         mPreference = (RadioButtonPreference)
128                 screen.findPreference(getPreferenceKey());
129         mPreference.setOnClickListener(this);
130     }
131 
132     @Override
onRadioButtonClicked(RadioButtonPreference preference)133     public void onRadioButtonClicked(RadioButtonPreference preference) {
134         int value = getTimeoutValueToKeyMap().get(mPreferenceKey);
135         handlePreferenceChange(String.valueOf(value));
136         if (mOnChangeListener != null) {
137             mOnChangeListener.onCheckedChanged(mPreference);
138         }
139     }
140 
getAccessibilityTimeoutValue()141     private int getAccessibilityTimeoutValue() {
142         // get accessibility control timeout value
143         int timeoutValue = getSecureAccessibilityTimeoutValue(mContentResolver,
144                 CONTROL_TIMEOUT_SETTINGS_SECURE);
145         return timeoutValue;
146     }
147 
updatePreferenceCheckedState(int value)148     protected void updatePreferenceCheckedState(int value) {
149         if (mAccessibilityUiTimeoutValue == value) {
150             mPreference.setChecked(true);
151         }
152     }
153 
154     @Override
updateState(Preference preference)155     public void updateState(Preference preference) {
156         super.updateState(preference);
157 
158         mAccessibilityUiTimeoutValue = getAccessibilityTimeoutValue();
159 
160         // reset RadioButton
161         mPreference.setChecked(false);
162         int preferenceValue = getTimeoutValueToKeyMap().get(mPreference.getKey());
163         updatePreferenceCheckedState(preferenceValue);
164     }
165 
166     /**
167      * Listener interface handles checked event.
168      */
169     public interface OnChangeListener {
170         /**
171          * A hook that is called when preference checked.
172          */
onCheckedChanged(Preference preference)173         void onCheckedChanged(Preference preference);
174     }
175 }
176