1 /* 2 * Copyright (C) 2024 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 package com.android.settings.accessibility; 17 18 import static com.android.settings.accessibility.DaltonizerPreferenceUtil.isSecureAccessibilityDaltonizerEnabled; 19 import static com.android.settings.accessibility.DaltonizerPreferenceUtil.getSecureAccessibilityDaltonizerValue; 20 21 import android.content.ContentResolver; 22 import android.content.Context; 23 import android.database.ContentObserver; 24 import android.os.Handler; 25 import android.os.Looper; 26 import android.provider.Settings; 27 28 import androidx.annotation.NonNull; 29 import androidx.annotation.Nullable; 30 import androidx.lifecycle.DefaultLifecycleObserver; 31 import androidx.lifecycle.LifecycleOwner; 32 import androidx.preference.Preference; 33 import androidx.preference.PreferenceScreen; 34 35 import com.android.server.accessibility.Flags; 36 import com.android.settings.R; 37 import com.android.settings.core.SliderPreferenceController; 38 import com.android.settings.widget.SeekBarPreference; 39 40 /** 41 * The controller of the seekbar preference for the saturation level of color correction. 42 */ 43 public class DaltonizerSaturationSeekbarPreferenceController 44 extends SliderPreferenceController 45 implements DefaultLifecycleObserver { 46 47 private static final int DEFAULT_SATURATION_LEVEL = 7; 48 private static final int SATURATION_MAX = 10; 49 private static final int SATURATION_MIN = 1; 50 51 private int mSliderPosition; 52 private final ContentResolver mContentResolver; 53 54 @Nullable 55 private SeekBarPreference mPreference; 56 57 public final ContentObserver mContentObserver = new ContentObserver( 58 new Handler(Looper.getMainLooper())) { 59 @Override 60 public void onChange(boolean selfChange) { 61 if (mPreference != null) { 62 updateState(mPreference); 63 } 64 } 65 }; 66 DaltonizerSaturationSeekbarPreferenceController(Context context, String preferenceKey)67 public DaltonizerSaturationSeekbarPreferenceController(Context context, 68 String preferenceKey) { 69 super(context, preferenceKey); 70 mContentResolver = context.getContentResolver(); 71 mSliderPosition = Settings.Secure.getInt( 72 mContentResolver, 73 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL, 74 DEFAULT_SATURATION_LEVEL); 75 setSliderPosition(mSliderPosition); 76 // TODO: Observer color correction on/off and enable/disable based on secure settings. 77 } 78 79 @Override onStart(@onNull LifecycleOwner owner)80 public void onStart(@NonNull LifecycleOwner owner) { 81 if (!isAvailable()) return; 82 mContentResolver.registerContentObserver( 83 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER), 84 true, 85 mContentObserver 86 ); 87 mContentResolver.registerContentObserver( 88 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED), 89 true, 90 mContentObserver 91 ); 92 } 93 94 @Override onStop(@onNull LifecycleOwner owner)95 public void onStop(@NonNull LifecycleOwner owner) { 96 if (!isAvailable()) return; 97 mContentResolver.unregisterContentObserver(mContentObserver); 98 mPreference = null; 99 } 100 101 @Override displayPreference(PreferenceScreen screen)102 public void displayPreference(PreferenceScreen screen) { 103 super.displayPreference(screen); 104 SeekBarPreference preference = screen.findPreference(getPreferenceKey()); 105 mPreference = preference; 106 preference.setMax(getMax()); 107 preference.setMin(getMin()); 108 preference.setProgress(mSliderPosition); 109 preference.setContinuousUpdates(true); 110 } 111 112 @Override getAvailabilityStatus()113 public int getAvailabilityStatus() { 114 if (Flags.enableColorCorrectionSaturation()) { 115 return shouldSeekBarEnabled() ? AVAILABLE : DISABLED_DEPENDENT_SETTING; 116 } 117 return CONDITIONALLY_UNAVAILABLE; 118 } 119 120 @Override getSliderPosition()121 public int getSliderPosition() { 122 return mSliderPosition; 123 } 124 125 @Override setSliderPosition(int position)126 public boolean setSliderPosition(int position) { 127 if (position < getMin() || position > getMax()) { 128 return false; 129 } 130 mSliderPosition = position; 131 Settings.Secure.putInt( 132 mContentResolver, 133 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL, 134 mSliderPosition); 135 return true; 136 } 137 138 @Override updateState(Preference preference)139 public void updateState(Preference preference) { 140 if (preference == null) { 141 return; 142 } 143 144 var shouldSeekbarEnabled = shouldSeekBarEnabled(); 145 // setSummary not working yet on SeekBarPreference. 146 String summary = shouldSeekbarEnabled 147 ? "" 148 : mContext.getString(R.string.daltonizer_saturation_unavailable_summary); 149 preference.setSummary(summary); 150 preference.setEnabled(shouldSeekbarEnabled); 151 } 152 153 @Override getMax()154 public int getMax() { 155 return SATURATION_MAX; 156 } 157 158 @Override getMin()159 public int getMin() { 160 return SATURATION_MIN; 161 } 162 shouldSeekBarEnabled()163 private boolean shouldSeekBarEnabled() { 164 boolean enabled = isSecureAccessibilityDaltonizerEnabled(mContentResolver); 165 int mode = getSecureAccessibilityDaltonizerValue(mContentResolver); 166 167 // mode == 0 is gray scale where saturation level isn't applicable. 168 // mode == -1 is disabled and also default. 169 return enabled && mode != -1 && mode != 0; 170 } 171 } 172