1 /*
2  * Copyright (C) 2014 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.qs;
18 
19 import android.content.Context;
20 import android.graphics.Point;
21 import android.util.AttributeSet;
22 import android.view.View;
23 import android.widget.FrameLayout;
24 
25 import com.android.systemui.R;
26 import com.android.systemui.qs.customize.QSCustomizer;
27 
28 /**
29  * Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader}
30  */
31 public class QSContainerImpl extends FrameLayout {
32 
33     private final Point mSizePoint = new Point();
34 
35     private int mHeightOverride = -1;
36     protected View mQSPanel;
37     private View mQSDetail;
38     protected View mHeader;
39     protected float mQsExpansion;
40     private QSCustomizer mQSCustomizer;
41     private QSFooter mQSFooter;
42     private int mGutterHeight;
43     private View mBackground;
44     private float mFullElevation;
45 
QSContainerImpl(Context context, AttributeSet attrs)46     public QSContainerImpl(Context context, AttributeSet attrs) {
47         super(context, attrs);
48     }
49 
50     @Override
onFinishInflate()51     protected void onFinishInflate() {
52         super.onFinishInflate();
53         mQSPanel = findViewById(R.id.quick_settings_panel);
54         mQSDetail = findViewById(R.id.qs_detail);
55         mHeader = findViewById(R.id.header);
56         mQSCustomizer = findViewById(R.id.qs_customize);
57         mQSFooter = findViewById(R.id.qs_footer);
58         mBackground = findViewById(R.id.qs_background);
59         mGutterHeight = getContext().getResources().getDimensionPixelSize(R.dimen.qs_gutter_height);
60         mFullElevation = mQSPanel.getElevation();
61 
62         setClickable(true);
63         setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
64     }
65 
66     @Override
performClick()67     public boolean performClick() {
68         // Want to receive clicks so missing QQS tiles doesn't cause collapse, but
69         // don't want to do anything with them.
70         return true;
71     }
72 
73     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)74     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
75         // Since we control our own bottom, be whatever size we want.
76         // Otherwise the QSPanel ends up with 0 height when the window is only the
77         // size of the status bar.
78         mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(
79                 MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED));
80         int width = mQSPanel.getMeasuredWidth();
81         LayoutParams layoutParams = (LayoutParams) mQSPanel.getLayoutParams();
82         int height = layoutParams.topMargin + layoutParams.bottomMargin
83                 + mQSPanel.getMeasuredHeight();
84         super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
85                 MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
86 
87         // QSCustomizer will always be the height of the screen, but do this after
88         // other measuring to avoid changing the height of the QS.
89         getDisplay().getRealSize(mSizePoint);
90         mQSCustomizer.measure(widthMeasureSpec,
91                 MeasureSpec.makeMeasureSpec(mSizePoint.y, MeasureSpec.EXACTLY));
92     }
93 
94     @Override
onLayout(boolean changed, int left, int top, int right, int bottom)95     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
96         super.onLayout(changed, left, top, right, bottom);
97         updateExpansion();
98     }
99 
100     /**
101      * Overrides the height of this view (post-layout), so that the content is clipped to that
102      * height and the background is set to that height.
103      *
104      * @param heightOverride the overridden height
105      */
setHeightOverride(int heightOverride)106     public void setHeightOverride(int heightOverride) {
107         mHeightOverride = heightOverride;
108         updateExpansion();
109     }
110 
updateExpansion()111     public void updateExpansion() {
112         int height = calculateContainerHeight();
113         int gutterHeight = Math.round(mQsExpansion * mGutterHeight);
114         setBottom(getTop() + height + gutterHeight);
115         mQSDetail.setBottom(getTop() + height);
116         mBackground.setBottom(getTop() + height);
117         // Pin QS Footer to the bottom of the panel.
118         mQSFooter.setTranslationY(height - mQSFooter.getHeight());
119 
120         float elevation = mQsExpansion * mFullElevation;
121         mQSDetail.setElevation(elevation);
122         mBackground.setElevation(elevation);
123         mQSFooter.setElevation(elevation);
124         mQSPanel.setElevation(elevation);
125     }
126 
calculateContainerHeight()127     protected int calculateContainerHeight() {
128         int heightOverride = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
129         return mQSCustomizer.isCustomizing() ? mQSCustomizer.getHeight()
130                 : Math.round(mQsExpansion * (heightOverride - mHeader.getHeight()))
131                 + mHeader.getHeight();
132     }
133 
setExpansion(float expansion)134     public void setExpansion(float expansion) {
135         mQsExpansion = expansion;
136         updateExpansion();
137     }
138 
setGutterEnabled(boolean gutterEnabled)139     public void setGutterEnabled(boolean gutterEnabled) {
140         if (gutterEnabled == (mGutterHeight != 0)) {
141             return;
142         }
143         if (gutterEnabled) {
144             mGutterHeight = getContext().getResources().getDimensionPixelSize(
145                     R.dimen.qs_gutter_height);
146         } else {
147             mGutterHeight = 0;
148         }
149         updateExpansion();
150     }
151 }
152