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