• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.provider.Settings.System.KEYBOARD_VIBRATION_ENABLED;
20 
21 import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
22 import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
23 
24 import android.app.settings.SettingsEnums;
25 import android.content.ContentResolver;
26 import android.content.Context;
27 import android.database.ContentObserver;
28 import android.net.Uri;
29 import android.os.Handler;
30 import android.os.VibrationAttributes;
31 import android.os.Vibrator;
32 import android.os.vibrator.Flags;
33 import android.provider.Settings;
34 import android.util.Log;
35 
36 import androidx.annotation.NonNull;
37 import androidx.annotation.Nullable;
38 import androidx.lifecycle.DefaultLifecycleObserver;
39 import androidx.lifecycle.LifecycleOwner;
40 import androidx.preference.Preference;
41 import androidx.preference.PreferenceScreen;
42 import androidx.preference.TwoStatePreference;
43 
44 import com.android.settings.R;
45 import com.android.settings.core.TogglePreferenceController;
46 import com.android.settings.overlay.FeatureFactory;
47 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
48 
49 
50 /**
51  * A preference controller to turn on/off keyboard vibration state with a single toggle.
52  */
53 public class KeyboardVibrationTogglePreferenceController extends TogglePreferenceController
54         implements DefaultLifecycleObserver {
55 
56     private static final String TAG = "KeyboardVibrateControl";
57 
58     private static final Uri MAIN_VIBRATION_SWITCH_URI =
59             Settings.System.getUriFor(VibrationPreferenceConfig.MAIN_SWITCH_SETTING_KEY);
60 
61     private final ContentObserver mContentObserver;
62 
63     private final Vibrator mVibrator;
64 
65     @Nullable
66     private TwoStatePreference mPreference;
67 
68     private MetricsFeatureProvider mMetricsFeatureProvider;
69 
KeyboardVibrationTogglePreferenceController(Context context, String preferenceKey)70     public KeyboardVibrationTogglePreferenceController(Context context, String preferenceKey) {
71         super(context, preferenceKey);
72         mVibrator = context.getSystemService(Vibrator.class);
73         mContentObserver = new ContentObserver(new Handler(/* async= */ true)) {
74             @Override
75             public void onChange(boolean selfChange, Uri uri) {
76                 if (uri.equals(MAIN_VIBRATION_SWITCH_URI)) {
77                     updateState(mPreference);
78                 } else {
79                     Log.w(TAG, "Unexpected uri change:" + uri);
80                 }
81             }
82         };
83         mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
84     }
85 
86     @Override
onStart(@onNull LifecycleOwner owner)87     public void onStart(@NonNull LifecycleOwner owner) {
88         mContext.getContentResolver().registerContentObserver(MAIN_VIBRATION_SWITCH_URI,
89                 /* notifyForDescendants= */ false, mContentObserver);
90     }
91 
92     @Override
onStop(@onNull LifecycleOwner owner)93     public void onStop(@NonNull LifecycleOwner owner) {
94         mContext.getContentResolver().unregisterContentObserver(mContentObserver);
95     }
96 
97     @Override
displayPreference(PreferenceScreen screen)98     public void displayPreference(PreferenceScreen screen) {
99         super.displayPreference(screen);
100         mPreference = screen.findPreference(getPreferenceKey());
101     }
102 
103     @Override
updateState(@ullable Preference preference)104     public void updateState(@Nullable Preference preference) {
105         if (preference != null) {
106             super.updateState(preference);
107             preference.setEnabled(isPreferenceEnabled());
108         }
109     }
110 
111     @Override
getAvailabilityStatus()112     public int getAvailabilityStatus() {
113         if (Flags.keyboardCategoryEnabled()
114                 && mContext.getResources().getBoolean(R.bool.config_keyboard_vibration_supported)
115                 && mContext.getResources().getFloat(
116                 com.android.internal.R.dimen.config_keyboardHapticFeedbackFixedAmplitude) > 0) {
117             return AVAILABLE;
118         }
119         return UNSUPPORTED_ON_DEVICE;
120     }
121 
122     @Override
isChecked()123     public boolean isChecked() {
124         // Always unchecked if the preference disabled
125         return isPreferenceEnabled() && isKeyboardVibrationSwitchEnabled();
126     }
127 
128     @Override
setChecked(boolean isChecked)129     public boolean setChecked(boolean isChecked) {
130         final boolean success = updateKeyboardVibrationSetting(isChecked);
131         mMetricsFeatureProvider.action(mContext,
132                 SettingsEnums.ACTION_KEYBOARD_VIBRATION_CHANGED, isChecked);
133         if (success && isChecked) {
134             // Play the preview vibration effect when the toggle is on.
135             final VibrationAttributes touchAttrs =
136                     VibrationPreferenceConfig.createPreviewVibrationAttributes(
137                             VibrationAttributes.USAGE_TOUCH);
138             final VibrationAttributes keyboardAttrs =
139                     new VibrationAttributes.Builder(touchAttrs)
140                             .setCategory(VibrationAttributes.CATEGORY_KEYBOARD)
141                             .build();
142             VibrationPreferenceConfig.playVibrationPreview(mVibrator, keyboardAttrs);
143         }
144         return true;
145     }
146 
147     @Override
getSliceHighlightMenuRes()148     public int getSliceHighlightMenuRes() {
149         return R.string.menu_key_accessibility;
150     }
151 
isPreferenceEnabled()152     private boolean isPreferenceEnabled() {
153         return VibrationPreferenceConfig.isMainVibrationSwitchEnabled(
154                 mContext.getContentResolver());
155     }
156 
isKeyboardVibrationSwitchEnabled()157     private boolean isKeyboardVibrationSwitchEnabled() {
158         return Settings.System.getInt(mContext.getContentResolver(), KEYBOARD_VIBRATION_ENABLED,
159                 mVibrator.isDefaultKeyboardVibrationEnabled() ? ON : OFF) == ON;
160     }
161 
updateKeyboardVibrationSetting(boolean enable)162     private boolean updateKeyboardVibrationSetting(boolean enable) {
163         final ContentResolver contentResolver = mContext.getContentResolver();
164         final boolean success = Settings.System.putInt(contentResolver,
165                 KEYBOARD_VIBRATION_ENABLED, enable ? ON : OFF);
166         contentResolver.notifyChange(Settings.System.getUriFor(KEYBOARD_VIBRATION_ENABLED),
167                 null /* observer */, ContentResolver.NOTIFY_NO_DELAY);
168         if (!success) {
169             Log.w(TAG, "Update settings database error!");
170         }
171         return success;
172     }
173 }
174