Home | History | Annotate | Download | only in qs
      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 
     54     public QSContainerImpl(Context context, AttributeSet attrs) {
     55         super(context, attrs);
     56     }
     57 
     58     @Override
     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
     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
     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
     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
    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 
    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 
    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      */
    149     public void setHeightOverride(int heightOverride) {
    150         mHeightOverride = heightOverride;
    151         updateExpansion();
    152     }
    153 
    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 
    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 
    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 
    181     public void setExpansion(float expansion) {
    182         mQsExpansion = expansion;
    183         updateExpansion();
    184     }
    185 
    186     private void setMargins() {
    187         setMargins(mQSDetail);
    188         setMargins(mBackground);
    189         setMargins(mQSFooter);
    190         mQSPanel.setMargins(mSideMargins);
    191         mHeader.setMargins(mSideMargins);
    192     }
    193 
    194     private void setMargins(View view) {
    195         FrameLayout.LayoutParams lp = (LayoutParams) view.getLayoutParams();
    196         lp.rightMargin = mSideMargins;
    197         lp.leftMargin = mSideMargins;
    198     }
    199 
    200     private int getDisplayHeight() {
    201         if (mSizePoint.y == 0) {
    202             getDisplay().getRealSize(mSizePoint);
    203         }
    204         return mSizePoint.y;
    205     }
    206 }
    207