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