1 /* 2 * Copyright (C) 2021 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.database.ContentObserver; 22 import android.os.Handler; 23 import android.os.Looper; 24 import android.provider.Settings; 25 26 import androidx.annotation.FloatRange; 27 import androidx.annotation.VisibleForTesting; 28 import androidx.preference.PreferenceScreen; 29 30 import com.android.settings.core.SliderPreferenceController; 31 import com.android.settings.widget.SeekBarPreference; 32 import com.android.settingslib.core.lifecycle.LifecycleObserver; 33 import com.android.settingslib.core.lifecycle.events.OnPause; 34 import com.android.settingslib.core.lifecycle.events.OnResume; 35 36 /** Preference controller that controls the transparency seekbar in accessibility button page. */ 37 public class FloatingMenuTransparencyPreferenceController extends SliderPreferenceController 38 implements LifecycleObserver, OnResume, OnPause { 39 40 @VisibleForTesting 41 @FloatRange(from = 0.0, to = 1.0) 42 static final float DEFAULT_TRANSPARENCY = 0.45f; 43 @VisibleForTesting 44 static final float MAXIMUM_TRANSPARENCY = 1.0f; 45 private static final int FADE_ENABLED = 1; 46 private static final float MIN_PROGRESS = 0f; 47 private static final float MAX_PROGRESS = 90f; 48 @VisibleForTesting 49 static final float PRECISION = 100f; 50 51 private final ContentResolver mContentResolver; 52 @VisibleForTesting 53 final ContentObserver mContentObserver; 54 private SeekBarPreference mPreference; 55 FloatingMenuTransparencyPreferenceController(Context context, String preferenceKey)56 public FloatingMenuTransparencyPreferenceController(Context context, 57 String preferenceKey) { 58 super(context, preferenceKey); 59 mContentResolver = context.getContentResolver(); 60 mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) { 61 @Override 62 public void onChange(boolean selfChange) { 63 updateAvailabilityStatus(); 64 } 65 }; 66 } 67 68 @Override getAvailabilityStatus()69 public int getAvailabilityStatus() { 70 return AccessibilityUtil.isFloatingMenuEnabled(mContext) 71 ? AVAILABLE : DISABLED_DEPENDENT_SETTING; 72 } 73 74 @Override displayPreference(PreferenceScreen screen)75 public void displayPreference(PreferenceScreen screen) { 76 super.displayPreference(screen); 77 78 mPreference = screen.findPreference(getPreferenceKey()); 79 mPreference.setContinuousUpdates(true); 80 mPreference.setMax(getMax()); 81 mPreference.setMin(getMin()); 82 mPreference.setHapticFeedbackMode(SeekBarPreference.HAPTIC_FEEDBACK_MODE_ON_ENDS); 83 84 updateAvailabilityStatus(); 85 updateState(mPreference); 86 } 87 88 @Override onResume()89 public void onResume() { 90 mContentResolver.registerContentObserver( 91 Settings.Secure.getUriFor( 92 Settings.Secure.ACCESSIBILITY_BUTTON_MODE), /* notifyForDescendants= */ 93 false, mContentObserver); 94 mContentResolver.registerContentObserver( 95 Settings.Secure.getUriFor( 96 Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED), 97 /* notifyForDescendants= */ false, mContentObserver); 98 } 99 100 @Override onPause()101 public void onPause() { 102 mContentResolver.unregisterContentObserver(mContentObserver); 103 } 104 105 @Override getSliderPosition()106 public int getSliderPosition() { 107 return convertTransparencyFloatToInt(getTransparency()); 108 } 109 110 @Override setSliderPosition(int position)111 public boolean setSliderPosition(int position) { 112 final float opacityValue = MAXIMUM_TRANSPARENCY - convertTransparencyIntToFloat(position); 113 return Settings.Secure.putFloat(mContentResolver, 114 Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY, opacityValue); 115 } 116 117 @Override getMax()118 public int getMax() { 119 return (int) MAX_PROGRESS; 120 } 121 122 @Override getMin()123 public int getMin() { 124 return (int) MIN_PROGRESS; 125 } 126 updateAvailabilityStatus()127 private void updateAvailabilityStatus() { 128 final boolean fadeEnabled = Settings.Secure.getInt(mContentResolver, 129 Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED, FADE_ENABLED) 130 == FADE_ENABLED; 131 132 mPreference.setEnabled(AccessibilityUtil.isFloatingMenuEnabled(mContext) && fadeEnabled); 133 } 134 convertTransparencyFloatToInt(float value)135 private int convertTransparencyFloatToInt(float value) { 136 return Math.round(value * PRECISION); 137 } 138 convertTransparencyIntToFloat(int value)139 private float convertTransparencyIntToFloat(int value) { 140 return (float) value / PRECISION; 141 } 142 getTransparency()143 private float getTransparency() { 144 float transparencyValue = MAXIMUM_TRANSPARENCY - (Settings.Secure.getFloat(mContentResolver, 145 Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY, DEFAULT_TRANSPARENCY)); 146 final float minValue = MIN_PROGRESS / PRECISION; 147 final float maxValue = MAX_PROGRESS / PRECISION; 148 149 return (transparencyValue < minValue || transparencyValue > maxValue) 150 ? DEFAULT_TRANSPARENCY : transparencyValue; 151 } 152 } 153