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