• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
20 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
21 
22 import android.content.Context;
23 import android.content.res.Configuration;
24 import android.graphics.Point;
25 import android.util.AttributeSet;
26 import android.view.View;
27 import android.widget.FrameLayout;
28 
29 import com.android.systemui.R;
30 import com.android.systemui.qs.customize.QSCustomizer;
31 
32 /**
33  * Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader}
34  */
35 public class QSContainerImpl extends FrameLayout {
36 
37     private final Point mSizePoint = new Point();
38 
39     private int mHeightOverride = -1;
40     private QSPanel mQSPanel;
41     private View mQSDetail;
42     private QuickStatusBarHeader mHeader;
43     private float mQsExpansion;
44     private QSCustomizer mQSCustomizer;
45     private View mQSFooter;
46 
47     private View mBackground;
48     private View mBackgroundGradient;
49     private View mStatusBarBackground;
50 
51     private int mSideMargins;
52     private boolean mQsDisabled;
53 
QSContainerImpl(Context context, AttributeSet attrs)54     public QSContainerImpl(Context context, AttributeSet attrs) {
55         super(context, attrs);
56     }
57 
58     @Override
onFinishInflate()59     protected void onFinishInflate() {
60         super.onFinishInflate();
61         mQSPanel = findViewById(R.id.quick_settings_panel);
62         mQSDetail = findViewById(R.id.qs_detail);
63         mHeader = findViewById(R.id.header);
64         mQSCustomizer = findViewById(R.id.qs_customize);
65         mQSFooter = findViewById(R.id.qs_footer);
66         mBackground = findViewById(R.id.quick_settings_background);
67         mStatusBarBackground = findViewById(R.id.quick_settings_status_bar_background);
68         mBackgroundGradient = findViewById(R.id.quick_settings_gradient_view);
69         mSideMargins = getResources().getDimensionPixelSize(R.dimen.notification_side_paddings);
70 
71         setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
72         setMargins();
73     }
74 
75     @Override
onConfigurationChanged(Configuration newConfig)76     protected void onConfigurationChanged(Configuration newConfig) {
77         super.onConfigurationChanged(newConfig);
78         setBackgroundGradientVisibility(newConfig);
79         updateResources();
80         mSizePoint.set(0, 0); // Will be retrieved on next measure pass.
81     }
82 
83     @Override
performClick()84     public boolean performClick() {
85         // Want to receive clicks so missing QQS tiles doesn't cause collapse, but
86         // don't want to do anything with them.
87         return true;
88     }
89 
90     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)91     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
92         // QSPanel will show as many rows as it can (up to TileLayout.MAX_ROWS) such that the
93         // bottom and footer are inside the screen.
94         Configuration config = getResources().getConfiguration();
95         boolean navBelow = config.smallestScreenWidthDp >= 600
96                 || config.orientation != Configuration.ORIENTATION_LANDSCAPE;
97         MarginLayoutParams layoutParams = (MarginLayoutParams) mQSPanel.getLayoutParams();
98 
99         // The footer is pinned to the bottom of QSPanel (same bottoms), therefore we don't need to
100         // subtract its height. We do not care if the collapsed notifications fit in the screen.
101         int maxQs = getDisplayHeight() - layoutParams.topMargin - layoutParams.bottomMargin
102                 - getPaddingBottom();
103         if (navBelow) {
104             maxQs -= getResources().getDimensionPixelSize(R.dimen.navigation_bar_height);
105         }
106         // Measure with EXACTLY. That way, PagedTileLayout will only use excess height and will be
107         // measured last, after other views and padding is accounted for.
108         mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.EXACTLY));
109         int width = mQSPanel.getMeasuredWidth();
110         int height = layoutParams.topMargin + layoutParams.bottomMargin
111                 + mQSPanel.getMeasuredHeight() + getPaddingBottom();
112         super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
113                 MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
114 
115         // QSCustomizer will always be the height of the screen, but do this after
116         // other measuring to avoid changing the height of the QS.
117         mQSCustomizer.measure(widthMeasureSpec,
118                 MeasureSpec.makeMeasureSpec(getDisplayHeight(), MeasureSpec.EXACTLY));
119     }
120 
121     @Override
onLayout(boolean changed, int left, int top, int right, int bottom)122     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
123         super.onLayout(changed, left, top, right, bottom);
124         updateExpansion();
125     }
126 
disable(int state1, int state2, boolean animate)127     public void disable(int state1, int state2, boolean animate) {
128         final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
129         if (disabled == mQsDisabled) return;
130         mQsDisabled = disabled;
131         setBackgroundGradientVisibility(getResources().getConfiguration());
132         mBackground.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
133     }
134 
updateResources()135     private void updateResources() {
136         LayoutParams layoutParams = (LayoutParams) mQSPanel.getLayoutParams();
137         layoutParams.topMargin = mContext.getResources().getDimensionPixelSize(
138                 com.android.internal.R.dimen.quick_qs_offset_height);
139 
140         mQSPanel.setLayoutParams(layoutParams);
141     }
142 
143     /**
144      * Overrides the height of this view (post-layout), so that the content is clipped to that
145      * height and the background is set to that height.
146      *
147      * @param heightOverride the overridden height
148      */
setHeightOverride(int heightOverride)149     public void setHeightOverride(int heightOverride) {
150         mHeightOverride = heightOverride;
151         updateExpansion();
152     }
153 
updateExpansion()154     public void updateExpansion() {
155         int height = calculateContainerHeight();
156         setBottom(getTop() + height);
157         mQSDetail.setBottom(getTop() + height);
158         // Pin QS Footer to the bottom of the panel.
159         mQSFooter.setTranslationY(height - mQSFooter.getHeight());
160         mBackground.setTop(mQSPanel.getTop());
161         mBackground.setBottom(height);
162     }
163 
calculateContainerHeight()164     protected int calculateContainerHeight() {
165         int heightOverride = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
166         return mQSCustomizer.isCustomizing() ? mQSCustomizer.getHeight()
167                 : Math.round(mQsExpansion * (heightOverride - mHeader.getHeight()))
168                 + mHeader.getHeight();
169     }
170 
setBackgroundGradientVisibility(Configuration newConfig)171     private void setBackgroundGradientVisibility(Configuration newConfig) {
172         if (newConfig.orientation == ORIENTATION_LANDSCAPE) {
173             mBackgroundGradient.setVisibility(View.INVISIBLE);
174             mStatusBarBackground.setVisibility(View.INVISIBLE);
175         } else {
176             mBackgroundGradient.setVisibility(mQsDisabled ? View.INVISIBLE : View.VISIBLE);
177             mStatusBarBackground.setVisibility(View.VISIBLE);
178         }
179     }
180 
setExpansion(float expansion)181     public void setExpansion(float expansion) {
182         mQsExpansion = expansion;
183         updateExpansion();
184     }
185 
setMargins()186     private void setMargins() {
187         setMargins(mQSDetail);
188         setMargins(mBackground);
189         setMargins(mQSFooter);
190         mQSPanel.setMargins(mSideMargins);
191         mHeader.setMargins(mSideMargins);
192     }
193 
setMargins(View view)194     private void setMargins(View view) {
195         FrameLayout.LayoutParams lp = (LayoutParams) view.getLayoutParams();
196         lp.rightMargin = mSideMargins;
197         lp.leftMargin = mSideMargins;
198     }
199 
getDisplayHeight()200     private int getDisplayHeight() {
201         if (mSizePoint.y == 0) {
202             getDisplay().getRealSize(mSizePoint);
203         }
204         return mSizePoint.y;
205     }
206 }
207