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