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.Context; 20 import android.os.Vibrator; 21 22 import androidx.preference.Preference; 23 import androidx.preference.PreferenceScreen; 24 25 import com.android.settings.R; 26 import com.android.settings.core.SliderPreferenceController; 27 import com.android.settings.widget.SeekBarPreference; 28 import com.android.settingslib.core.lifecycle.LifecycleObserver; 29 import com.android.settingslib.core.lifecycle.events.OnStart; 30 import com.android.settingslib.core.lifecycle.events.OnStop; 31 32 /** 33 * Abstract preference controller for a vibration intensity setting, that displays multiple 34 * intensity levels to the user as a slider. 35 */ 36 public abstract class VibrationIntensityPreferenceController extends SliderPreferenceController 37 implements LifecycleObserver, OnStart, OnStop { 38 39 protected final VibrationPreferenceConfig mPreferenceConfig; 40 private final VibrationPreferenceConfig.SettingObserver mSettingsContentObserver; 41 private final int mMaxIntensity; 42 VibrationIntensityPreferenceController(Context context, String prefkey, VibrationPreferenceConfig preferenceConfig)43 protected VibrationIntensityPreferenceController(Context context, String prefkey, 44 VibrationPreferenceConfig preferenceConfig) { 45 this(context, prefkey, preferenceConfig, 46 context.getResources().getInteger( 47 R.integer.config_vibration_supported_intensity_levels)); 48 } 49 VibrationIntensityPreferenceController(Context context, String prefkey, VibrationPreferenceConfig preferenceConfig, int supportedIntensityLevels)50 protected VibrationIntensityPreferenceController(Context context, String prefkey, 51 VibrationPreferenceConfig preferenceConfig, int supportedIntensityLevels) { 52 super(context, prefkey); 53 mPreferenceConfig = preferenceConfig; 54 mSettingsContentObserver = new VibrationPreferenceConfig.SettingObserver( 55 preferenceConfig); 56 mMaxIntensity = Math.min(Vibrator.VIBRATION_INTENSITY_HIGH, supportedIntensityLevels); 57 } 58 59 @Override onStart()60 public void onStart() { 61 mSettingsContentObserver.register(mContext); 62 } 63 64 @Override onStop()65 public void onStop() { 66 mSettingsContentObserver.unregister(mContext); 67 } 68 69 @Override displayPreference(PreferenceScreen screen)70 public void displayPreference(PreferenceScreen screen) { 71 super.displayPreference(screen); 72 final SeekBarPreference preference = screen.findPreference(getPreferenceKey()); 73 mSettingsContentObserver.onDisplayPreference(this, preference); 74 preference.setEnabled(mPreferenceConfig.isPreferenceEnabled()); 75 preference.setSummaryProvider(unused -> mPreferenceConfig.getSummary()); 76 preference.setMin(getMin()); 77 preference.setMax(getMax()); 78 // Haptics previews played by the Settings app don't bypass user settings to be played. 79 // The sliders continuously updates the intensity value so the previews can apply them. 80 preference.setContinuousUpdates(true); 81 } 82 83 @Override updateState(Preference preference)84 public void updateState(Preference preference) { 85 super.updateState(preference); 86 if (preference != null) { 87 preference.setEnabled(mPreferenceConfig.isPreferenceEnabled()); 88 } 89 } 90 91 @Override getMin()92 public int getMin() { 93 return Vibrator.VIBRATION_INTENSITY_OFF; 94 } 95 96 @Override getMax()97 public int getMax() { 98 return mMaxIntensity; 99 } 100 101 @Override getSliderPosition()102 public int getSliderPosition() { 103 if (!mPreferenceConfig.isPreferenceEnabled()) { 104 return getMin(); 105 } 106 final int position = mPreferenceConfig.readIntensity(); 107 return Math.min(position, getMax()); 108 } 109 110 @Override setSliderPosition(int position)111 public boolean setSliderPosition(int position) { 112 if (!mPreferenceConfig.isPreferenceEnabled()) { 113 // Ignore slider updates when the preference is disabled. 114 return false; 115 } 116 final int intensity = calculateVibrationIntensity(position); 117 final boolean success = mPreferenceConfig.updateIntensity(intensity); 118 119 if (success && (position != Vibrator.VIBRATION_INTENSITY_OFF)) { 120 mPreferenceConfig.playVibrationPreview(); 121 } 122 123 return success; 124 } 125 calculateVibrationIntensity(int position)126 private int calculateVibrationIntensity(int position) { 127 int maxPosition = getMax(); 128 if (position >= maxPosition) { 129 if (maxPosition == 1) { 130 // If there is only one intensity available besides OFF, then use the device default 131 // intensity to ensure no scaling will ever happen in the platform. 132 return mPreferenceConfig.getDefaultIntensity(); 133 } 134 // If the settings granularity is lower than the platform's then map the max position to 135 // the highest vibration intensity, skipping intermediate values in the scale. 136 return Vibrator.VIBRATION_INTENSITY_HIGH; 137 } 138 return position; 139 } 140 } 141