1 /* 2 * Copyright (C) 2020 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.systemui.settings.brightness; 18 19 import android.content.Context; 20 import android.graphics.Rect; 21 import android.graphics.drawable.Drawable; 22 import android.graphics.drawable.DrawableWrapper; 23 import android.graphics.drawable.LayerDrawable; 24 import android.util.AttributeSet; 25 import android.view.MotionEvent; 26 import android.view.View; 27 import android.widget.FrameLayout; 28 import android.widget.SeekBar.OnSeekBarChangeListener; 29 30 import androidx.annotation.Keep; 31 import androidx.annotation.NonNull; 32 import androidx.annotation.Nullable; 33 34 import com.android.settingslib.RestrictedLockUtils; 35 import com.android.systemui.Gefingerpoken; 36 import com.android.systemui.R; 37 38 /** 39 * {@code FrameLayout} used to show and manipulate a {@link ToggleSeekBar}. 40 * 41 */ 42 public class BrightnessSliderView extends FrameLayout { 43 44 @NonNull 45 private ToggleSeekBar mSlider; 46 private DispatchTouchEventListener mListener; 47 private Gefingerpoken mOnInterceptListener; 48 @Nullable 49 private Drawable mProgressDrawable; 50 private float mScale = 1f; 51 BrightnessSliderView(Context context)52 public BrightnessSliderView(Context context) { 53 this(context, null); 54 } 55 BrightnessSliderView(Context context, AttributeSet attrs)56 public BrightnessSliderView(Context context, AttributeSet attrs) { 57 super(context, attrs); 58 } 59 60 // Inflated from quick_settings_brightness_dialog 61 @Override onFinishInflate()62 protected void onFinishInflate() { 63 super.onFinishInflate(); 64 setLayerType(LAYER_TYPE_HARDWARE, null); 65 66 mSlider = requireViewById(R.id.slider); 67 mSlider.setAccessibilityLabel(getContentDescription().toString()); 68 69 // Finds the progress drawable. Assumes brightness_progress_drawable.xml 70 try { 71 LayerDrawable progress = (LayerDrawable) mSlider.getProgressDrawable(); 72 DrawableWrapper progressSlider = (DrawableWrapper) progress 73 .findDrawableByLayerId(android.R.id.progress); 74 LayerDrawable actualProgressSlider = (LayerDrawable) progressSlider.getDrawable(); 75 mProgressDrawable = actualProgressSlider.findDrawableByLayerId(R.id.slider_foreground); 76 } catch (Exception e) { 77 // Nothing to do, mProgressDrawable will be null. 78 } 79 } 80 81 /** 82 * Attaches a listener to relay touch events. 83 * @param listener use {@code null} to remove listener 84 */ setOnDispatchTouchEventListener( DispatchTouchEventListener listener)85 public void setOnDispatchTouchEventListener( 86 DispatchTouchEventListener listener) { 87 mListener = listener; 88 } 89 90 @Override dispatchTouchEvent(MotionEvent ev)91 public boolean dispatchTouchEvent(MotionEvent ev) { 92 if (mListener != null) { 93 mListener.onDispatchTouchEvent(ev); 94 } 95 return super.dispatchTouchEvent(ev); 96 } 97 98 @Override requestDisallowInterceptTouchEvent(boolean disallowIntercept)99 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { 100 // We prevent disallowing on this view, but bubble it up to our parents. 101 // We need interception to handle falsing. 102 if (mParent != null) { 103 mParent.requestDisallowInterceptTouchEvent(disallowIntercept); 104 } 105 } 106 107 /** 108 * Attaches a listener to the {@link ToggleSeekBar} in the view so changes can be observed 109 * @param seekListener use {@code null} to remove listener 110 */ setOnSeekBarChangeListener(OnSeekBarChangeListener seekListener)111 public void setOnSeekBarChangeListener(OnSeekBarChangeListener seekListener) { 112 mSlider.setOnSeekBarChangeListener(seekListener); 113 } 114 115 /** 116 * Enforces admin rules for toggling auto-brightness and changing value of brightness 117 * @param admin 118 * @see ToggleSeekBar#setEnforcedAdmin 119 */ setEnforcedAdmin(RestrictedLockUtils.EnforcedAdmin admin)120 public void setEnforcedAdmin(RestrictedLockUtils.EnforcedAdmin admin) { 121 mSlider.setEnabled(admin == null); 122 mSlider.setEnforcedAdmin(admin); 123 } 124 125 /** 126 * Enables or disables the slider 127 * @param enable 128 */ enableSlider(boolean enable)129 public void enableSlider(boolean enable) { 130 mSlider.setEnabled(enable); 131 } 132 133 /** 134 * @return the maximum value of the {@link ToggleSeekBar}. 135 */ getMax()136 public int getMax() { 137 return mSlider.getMax(); 138 } 139 140 /** 141 * Sets the maximum value of the {@link ToggleSeekBar}. 142 * @param max 143 */ setMax(int max)144 public void setMax(int max) { 145 mSlider.setMax(max); 146 } 147 148 /** 149 * Sets the current value of the {@link ToggleSeekBar}. 150 * @param value 151 */ setValue(int value)152 public void setValue(int value) { 153 mSlider.setProgress(value); 154 } 155 156 /** 157 * @return the current value of the {@link ToggleSeekBar} 158 */ getValue()159 public int getValue() { 160 return mSlider.getProgress(); 161 } 162 setOnInterceptListener(Gefingerpoken onInterceptListener)163 public void setOnInterceptListener(Gefingerpoken onInterceptListener) { 164 mOnInterceptListener = onInterceptListener; 165 } 166 167 @Override onInterceptTouchEvent(MotionEvent ev)168 public boolean onInterceptTouchEvent(MotionEvent ev) { 169 if (mOnInterceptListener != null) { 170 return mOnInterceptListener.onInterceptTouchEvent(ev); 171 } 172 return super.onInterceptTouchEvent(ev); 173 } 174 175 @Override onLayout(boolean changed, int left, int top, int right, int bottom)176 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 177 super.onLayout(changed, left, top, right, bottom); 178 applySliderScale(); 179 } 180 181 /** 182 * Sets the scale for the progress bar (for brightness_progress_drawable.xml) 183 * 184 * This will only scale the thick progress bar and not the icon inside 185 * 186 * Used in {@link com.android.systemui.qs.QSAnimator}. 187 */ 188 @Keep setSliderScaleY(float scale)189 public void setSliderScaleY(float scale) { 190 if (scale != mScale) { 191 mScale = scale; 192 applySliderScale(); 193 } 194 } 195 applySliderScale()196 private void applySliderScale() { 197 if (mProgressDrawable != null) { 198 final Rect r = mProgressDrawable.getBounds(); 199 int height = (int) (mProgressDrawable.getIntrinsicHeight() * mScale); 200 int inset = (mProgressDrawable.getIntrinsicHeight() - height) / 2; 201 mProgressDrawable.setBounds(r.left, inset, r.right, inset + height); 202 } 203 } 204 205 @Keep getSliderScaleY()206 public float getSliderScaleY() { 207 return mScale; 208 } 209 210 /** 211 * Interface to attach a listener for {@link View#dispatchTouchEvent}. 212 */ 213 @FunctionalInterface 214 interface DispatchTouchEventListener { onDispatchTouchEvent(MotionEvent ev)215 boolean onDispatchTouchEvent(MotionEvent ev); 216 } 217 } 218 219