Home | History | Annotate | Download | only in qs
      1 /*
      2  * Copyright (C) 2015 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 com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
     20 
     21 import android.content.Context;
     22 import android.content.res.Configuration;
     23 import android.graphics.Rect;
     24 import android.util.AttributeSet;
     25 import android.view.Gravity;
     26 import android.view.View;
     27 import android.widget.LinearLayout;
     28 
     29 import com.android.systemui.Dependency;
     30 import com.android.systemui.DumpController;
     31 import com.android.systemui.R;
     32 import com.android.systemui.plugins.qs.QSTile;
     33 import com.android.systemui.plugins.qs.QSTile.SignalState;
     34 import com.android.systemui.plugins.qs.QSTile.State;
     35 import com.android.systemui.qs.customize.QSCustomizer;
     36 import com.android.systemui.tuner.TunerService;
     37 import com.android.systemui.tuner.TunerService.Tunable;
     38 
     39 import java.util.ArrayList;
     40 import java.util.Collection;
     41 
     42 import javax.inject.Inject;
     43 import javax.inject.Named;
     44 
     45 /**
     46  * Version of QSPanel that only shows N Quick Tiles in the QS Header.
     47  */
     48 public class QuickQSPanel extends QSPanel {
     49 
     50     public static final String NUM_QUICK_TILES = "sysui_qqs_count";
     51     private static final String TAG = "QuickQSPanel";
     52 
     53     private boolean mDisabledByPolicy;
     54     private static int mDefaultMaxTiles;
     55     private int mMaxTiles;
     56     protected QSPanel mFullPanel;
     57 
     58     @Inject
     59     public QuickQSPanel(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
     60             DumpController dumpController) {
     61         super(context, attrs, dumpController);
     62         if (mFooter != null) {
     63             removeView(mFooter.getView());
     64         }
     65         if (mTileLayout != null) {
     66             for (int i = 0; i < mRecords.size(); i++) {
     67                 mTileLayout.removeTile(mRecords.get(i));
     68             }
     69             removeView((View) mTileLayout);
     70         }
     71         mDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
     72         mTileLayout = new HeaderTileLayout(context);
     73         mTileLayout.setListening(mListening);
     74         addView((View) mTileLayout, 0 /* Between brightness and footer */);
     75         super.setPadding(0, 0, 0, 0);
     76     }
     77 
     78     @Override
     79     public void setPadding(int left, int top, int right, int bottom) {
     80         // Always have no padding.
     81     }
     82 
     83     @Override
     84     protected void addDivider() {
     85     }
     86 
     87     @Override
     88     protected void onAttachedToWindow() {
     89         super.onAttachedToWindow();
     90         Dependency.get(TunerService.class).addTunable(mNumTiles, NUM_QUICK_TILES);
     91     }
     92 
     93     @Override
     94     protected void onDetachedFromWindow() {
     95         super.onDetachedFromWindow();
     96         Dependency.get(TunerService.class).removeTunable(mNumTiles);
     97     }
     98 
     99     public void setQSPanelAndHeader(QSPanel fullPanel, View header) {
    100         mFullPanel = fullPanel;
    101     }
    102 
    103     @Override
    104     protected boolean shouldShowDetail() {
    105         return !mExpanded;
    106     }
    107 
    108     @Override
    109     protected void drawTile(TileRecord r, State state) {
    110         if (state instanceof SignalState) {
    111             SignalState copy = new SignalState();
    112             state.copyTo(copy);
    113             // No activity shown in the quick panel.
    114             copy.activityIn = false;
    115             copy.activityOut = false;
    116             state = copy;
    117         }
    118         super.drawTile(r, state);
    119     }
    120 
    121     @Override
    122     public void setHost(QSTileHost host, QSCustomizer customizer) {
    123         super.setHost(host, customizer);
    124         setTiles(mHost.getTiles());
    125     }
    126 
    127     public void setMaxTiles(int maxTiles) {
    128         mMaxTiles = maxTiles;
    129         if (mHost != null) {
    130             setTiles(mHost.getTiles());
    131         }
    132     }
    133 
    134     @Override
    135     public void onTuningChanged(String key, String newValue) {
    136         if (QS_SHOW_BRIGHTNESS.equals(key)) {
    137             // No Brightness or Tooltip for you!
    138             super.onTuningChanged(key, "0");
    139         }
    140     }
    141 
    142     @Override
    143     public void setTiles(Collection<QSTile> tiles) {
    144         ArrayList<QSTile> quickTiles = new ArrayList<>();
    145         for (QSTile tile : tiles) {
    146             quickTiles.add(tile);
    147             if (quickTiles.size() == mMaxTiles) {
    148                 break;
    149             }
    150         }
    151         super.setTiles(quickTiles, true);
    152     }
    153 
    154     private final Tunable mNumTiles = new Tunable() {
    155         @Override
    156         public void onTuningChanged(String key, String newValue) {
    157             setMaxTiles(getNumQuickTiles(mContext));
    158         }
    159     };
    160 
    161     public static int getNumQuickTiles(Context context) {
    162         return Dependency.get(TunerService.class).getValue(NUM_QUICK_TILES, mDefaultMaxTiles);
    163     }
    164 
    165     void setDisabledByPolicy(boolean disabled) {
    166         if (disabled != mDisabledByPolicy) {
    167             mDisabledByPolicy = disabled;
    168             setVisibility(disabled ? View.GONE : View.VISIBLE);
    169         }
    170     }
    171 
    172     /**
    173      * Sets the visibility of this {@link QuickQSPanel}. This method has no effect when this panel
    174      * is disabled by policy through {@link #setDisabledByPolicy(boolean)}, and in this case the
    175      * visibility will always be {@link View#GONE}. This method is called externally by
    176      * {@link QSAnimator} only.
    177      */
    178     @Override
    179     public void setVisibility(int visibility) {
    180         if (mDisabledByPolicy) {
    181             if (getVisibility() == View.GONE) {
    182                 return;
    183             }
    184             visibility = View.GONE;
    185         }
    186         super.setVisibility(visibility);
    187     }
    188 
    189     private static class HeaderTileLayout extends TileLayout {
    190 
    191         private boolean mListening;
    192         private Rect mClippingBounds = new Rect();
    193 
    194         public HeaderTileLayout(Context context) {
    195             super(context);
    196             setClipChildren(false);
    197             setClipToPadding(false);
    198             LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
    199                     LayoutParams.MATCH_PARENT);
    200             lp.gravity = Gravity.CENTER_HORIZONTAL;
    201             setLayoutParams(lp);
    202         }
    203 
    204         @Override
    205         protected void onConfigurationChanged(Configuration newConfig) {
    206             super.onConfigurationChanged(newConfig);
    207             updateResources();
    208         }
    209 
    210         @Override
    211         public void onFinishInflate(){
    212             updateResources();
    213         }
    214 
    215         private LayoutParams generateTileLayoutParams() {
    216             LayoutParams lp = new LayoutParams(mCellWidth, mCellHeight);
    217             return lp;
    218         }
    219 
    220         @Override
    221         protected void addTileView(TileRecord tile) {
    222             addView(tile.tileView, getChildCount(), generateTileLayoutParams());
    223         }
    224 
    225         @Override
    226         protected void onLayout(boolean changed, int l, int t, int r, int b) {
    227             // We only care about clipping on the right side
    228             mClippingBounds.set(0, 0, r - l, 10000);
    229             setClipBounds(mClippingBounds);
    230 
    231             calculateColumns();
    232 
    233             for (int i = 0; i < mRecords.size(); i++) {
    234                 mRecords.get(i).tileView.setVisibility( i < mColumns ? View.VISIBLE : View.GONE);
    235             }
    236 
    237             setAccessibilityOrder();
    238             layoutTileRecords(mColumns);
    239         }
    240 
    241         @Override
    242         public boolean updateResources() {
    243             mCellWidth = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
    244             mCellHeight = mCellWidth;
    245 
    246             return false;
    247         }
    248 
    249         private boolean calculateColumns() {
    250             int prevNumColumns = mColumns;
    251             int maxTiles = mRecords.size();
    252 
    253             if (maxTiles == 0){ // Early return during setup
    254                 mColumns = 0;
    255                 return true;
    256             }
    257 
    258             final int availableWidth = getMeasuredWidth() - getPaddingStart() - getPaddingEnd();
    259             final int leftoverWhitespace = availableWidth - maxTiles * mCellWidth;
    260             final int smallestHorizontalMarginNeeded;
    261             smallestHorizontalMarginNeeded = leftoverWhitespace / Math.max(1, maxTiles - 1);
    262 
    263             if (smallestHorizontalMarginNeeded > 0){
    264                 mCellMarginHorizontal = smallestHorizontalMarginNeeded;
    265                 mColumns = maxTiles;
    266             } else{
    267                 mColumns = mCellWidth == 0 ? 1 :
    268                         Math.min(maxTiles, availableWidth / mCellWidth );
    269                 mCellMarginHorizontal = (availableWidth - mColumns * mCellWidth) / (mColumns - 1);
    270             }
    271             return mColumns != prevNumColumns;
    272         }
    273 
    274         private void setAccessibilityOrder() {
    275             if (mRecords != null && mRecords.size() > 0) {
    276                 View previousView = this;
    277                 for (TileRecord record : mRecords) {
    278                     if (record.tileView.getVisibility() == GONE) continue;
    279                     previousView = record.tileView.updateAccessibilityOrder(previousView);
    280                 }
    281                 mRecords.get(mRecords.size() - 1).tileView.setAccessibilityTraversalBefore(
    282                         R.id.expand_indicator);
    283             }
    284         }
    285 
    286         @Override
    287         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    288             // Measure each QS tile.
    289             for (TileRecord record : mRecords) {
    290                 if (record.tileView.getVisibility() == GONE) continue;
    291                 record.tileView.measure(exactly(mCellWidth), exactly(mCellHeight));
    292             }
    293 
    294             int height = mCellHeight;
    295             if (height < 0) height = 0;
    296 
    297             setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height);
    298         }
    299 
    300         @Override
    301         public int getNumVisibleTiles() {
    302             return mColumns;
    303         }
    304 
    305         @Override
    306         protected int getColumnStart(int column) {
    307             return getPaddingStart() + column *  (mCellWidth + mCellMarginHorizontal);
    308         }
    309     }
    310 }
    311