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 
21 import android.content.Context;
22 import android.content.res.Configuration;
23 import android.graphics.Point;
24 import android.util.AttributeSet;
25 import android.view.View;
26 import android.widget.FrameLayout;
27 
28 import com.android.systemui.R;
29 import com.android.systemui.SysUiServiceProvider;
30 import com.android.systemui.qs.customize.QSCustomizer;
31 import com.android.systemui.statusbar.CommandQueue;
32 
33 /**
34  * Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader}
35  */
36 public class QSContainerImpl extends FrameLayout {
37 
38     private final Point mSizePoint = new Point();
39 
40     private int mHeightOverride = -1;
41     private QSPanel mQSPanel;
42     private View mQSDetail;
43     private QuickStatusBarHeader mHeader;
44     private float mQsExpansion;
45     private QSCustomizer mQSCustomizer;
46     private View mQSFooter;
47 
48     private View mBackground;
49     private View mBackgroundGradient;
50     private View mStatusBarBackground;
51 
52     private int mSideMargins;
53     private boolean mQsDisabled;
54 
QSContainerImpl(Context context, AttributeSet attrs)55     public QSContainerImpl(Context context, AttributeSet attrs) {
56         super(context, attrs);
57     }
58 
59     @Override
onFinishInflate()60     protected void onFinishInflate() {
61         super.onFinishInflate();
62         mQSPanel = findViewById(R.id.quick_settings_panel);
63         mQSDetail = findViewById(R.id.qs_detail);
64         mHeader = findViewById(R.id.header);
65         mQSCustomizer = findViewById(R.id.qs_customize);
66         mQSFooter = findViewById(R.id.qs_footer);
67         mBackground = findViewById(R.id.quick_settings_background);
68         mStatusBarBackground = findViewById(R.id.quick_settings_status_bar_background);
69         mBackgroundGradient = findViewById(R.id.quick_settings_gradient_view);
70         mSideMargins = getResources().getDimensionPixelSize(R.dimen.notification_side_paddings);
71 
72         setClickable(true);
73         setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
74         setMargins();
75     }
76 
77     @Override
onConfigurationChanged(Configuration newConfig)78     protected void onConfigurationChanged(Configuration newConfig) {
79         super.onConfigurationChanged(newConfig);
80 
81         // Hide the backgrounds when in landscape mode.
82         if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
83             mBackgroundGradient.setVisibility(View.INVISIBLE);
84             mStatusBarBackground.setVisibility(View.INVISIBLE);
85         } else {
86             mBackgroundGradient.setVisibility(View.VISIBLE);
87             mStatusBarBackground.setVisibility(View.VISIBLE);
88         }
89 
90         updateResources();
91         mSizePoint.set(0, 0); // Will be retrieved on next measure pass.
92     }
93 
94     @Override
performClick()95     public boolean performClick() {
96         // Want to receive clicks so missing QQS tiles doesn't cause collapse, but
97         // don't want to do anything with them.
98         return true;
99     }
100 
101     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)102     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
103         // Since we control our own bottom, be whatever size we want.
104         // Otherwise the QSPanel ends up with 0 height when the window is only the
105         // size of the status bar.
106         mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(
107                 MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED));
108         int width = mQSPanel.getMeasuredWidth();
109         LayoutParams layoutParams = (LayoutParams) mQSPanel.getLayoutParams();
110         int height = layoutParams.topMargin + layoutParams.bottomMargin
111                 + mQSPanel.getMeasuredHeight();
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         mBackgroundGradient.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
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 
setExpansion(float expansion)171     public void setExpansion(float expansion) {
172         mQsExpansion = expansion;
173         updateExpansion();
174     }
175 
setMargins()176     private void setMargins() {
177         setMargins(mQSDetail);
178         setMargins(mBackground);
179         setMargins(mQSFooter);
180         mQSPanel.setMargins(mSideMargins);
181         mHeader.setMargins(mSideMargins);
182     }
183 
setMargins(View view)184     private void setMargins(View view) {
185         FrameLayout.LayoutParams lp = (LayoutParams) view.getLayoutParams();
186         lp.rightMargin = mSideMargins;
187         lp.leftMargin = mSideMargins;
188     }
189 
getDisplayHeight()190     private int getDisplayHeight() {
191         if (mSizePoint.y == 0) {
192             getDisplay().getRealSize(mSizePoint);
193         }
194         return mSizePoint.y;
195     }
196 }
197