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 android.content.Context;
     20 import android.content.res.Configuration;
     21 import android.util.AttributeSet;
     22 import android.view.Gravity;
     23 import android.view.View;
     24 import android.widget.LinearLayout;
     25 import android.widget.Space;
     26 
     27 import com.android.systemui.R;
     28 import com.android.systemui.qs.QSTile.SignalState;
     29 import com.android.systemui.qs.QSTile.State;
     30 import com.android.systemui.qs.customize.QSCustomizer;
     31 import com.android.systemui.statusbar.phone.QSTileHost;
     32 import com.android.systemui.tuner.TunerService;
     33 import com.android.systemui.tuner.TunerService.Tunable;
     34 
     35 import java.util.ArrayList;
     36 import java.util.Collection;
     37 
     38 /**
     39  * Version of QSPanel that only shows N Quick Tiles in the QS Header.
     40  */
     41 public class QuickQSPanel extends QSPanel {
     42 
     43     public static final String NUM_QUICK_TILES = "sysui_qqs_count";
     44 
     45     private int mMaxTiles;
     46     private QSPanel mFullPanel;
     47     private View mHeader;
     48 
     49     public QuickQSPanel(Context context, AttributeSet attrs) {
     50         super(context, attrs);
     51         if (mTileLayout != null) {
     52             for (int i = 0; i < mRecords.size(); i++) {
     53                 mTileLayout.removeTile(mRecords.get(i));
     54             }
     55             removeView((View) mTileLayout);
     56         }
     57         mTileLayout = new HeaderTileLayout(context);
     58         mTileLayout.setListening(mListening);
     59         addView((View) mTileLayout, 1 /* Between brightness and footer */);
     60     }
     61 
     62     @Override
     63     protected void onAttachedToWindow() {
     64         super.onAttachedToWindow();
     65         TunerService.get(mContext).addTunable(mNumTiles, NUM_QUICK_TILES);
     66     }
     67 
     68     @Override
     69     protected void onDetachedFromWindow() {
     70         super.onDetachedFromWindow();
     71         TunerService.get(mContext).removeTunable(mNumTiles);
     72     }
     73 
     74     public void setQSPanelAndHeader(QSPanel fullPanel, View header) {
     75         mFullPanel = fullPanel;
     76         mHeader = header;
     77     }
     78 
     79     @Override
     80     protected boolean shouldShowDetail() {
     81         return !mExpanded;
     82     }
     83 
     84     @Override
     85     protected void drawTile(TileRecord r, State state) {
     86         if (state instanceof SignalState) {
     87             State copy = r.tile.newTileState();
     88             state.copyTo(copy);
     89             // No activity shown in the quick panel.
     90             ((SignalState) copy).activityIn = false;
     91             ((SignalState) copy).activityOut = false;
     92             state = copy;
     93         }
     94         super.drawTile(r, state);
     95     }
     96 
     97     @Override
     98     protected QSTileBaseView createTileView(QSTile<?> tile, boolean collapsedView) {
     99         return new QSTileBaseView(mContext, tile.createTileView(mContext), collapsedView);
    100     }
    101 
    102     @Override
    103     public void setHost(QSTileHost host, QSCustomizer customizer) {
    104         super.setHost(host, customizer);
    105         setTiles(mHost.getTiles());
    106     }
    107 
    108     public void setMaxTiles(int maxTiles) {
    109         mMaxTiles = maxTiles;
    110         if (mHost != null) {
    111             setTiles(mHost.getTiles());
    112         }
    113     }
    114 
    115     @Override
    116     protected void onTileClick(QSTile<?> tile) {
    117         tile.secondaryClick();
    118     }
    119 
    120     @Override
    121     public void onTuningChanged(String key, String newValue) {
    122         // No tunings for you.
    123         if (key.equals(QS_SHOW_BRIGHTNESS)) {
    124             // No Brightness for you.
    125             super.onTuningChanged(key, "0");
    126         }
    127     }
    128 
    129     @Override
    130     public void setTiles(Collection<QSTile<?>> tiles) {
    131         ArrayList<QSTile<?>> quickTiles = new ArrayList<>();
    132         for (QSTile<?> tile : tiles) {
    133             quickTiles.add(tile);
    134             if (quickTiles.size() == mMaxTiles) {
    135                 break;
    136             }
    137         }
    138         super.setTiles(quickTiles, true);
    139     }
    140 
    141     private final Tunable mNumTiles = new Tunable() {
    142         @Override
    143         public void onTuningChanged(String key, String newValue) {
    144             setMaxTiles(getNumQuickTiles(mContext));
    145         }
    146     };
    147 
    148     public int getNumQuickTiles(Context context) {
    149         return TunerService.get(context).getValue(NUM_QUICK_TILES, 5);
    150     }
    151 
    152     private static class HeaderTileLayout extends LinearLayout implements QSTileLayout {
    153 
    154         private final Space mEndSpacer;
    155         protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
    156         private boolean mListening;
    157 
    158         public HeaderTileLayout(Context context) {
    159             super(context);
    160             setClipChildren(false);
    161             setClipToPadding(false);
    162             setGravity(Gravity.CENTER_VERTICAL);
    163             setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
    164 
    165             mEndSpacer = new Space(context);
    166             mEndSpacer.setLayoutParams(generateLayoutParams());
    167             updateDownArrowMargin();
    168             addView(mEndSpacer);
    169             setOrientation(LinearLayout.HORIZONTAL);
    170         }
    171 
    172         @Override
    173         protected void onConfigurationChanged(Configuration newConfig) {
    174             super.onConfigurationChanged(newConfig);
    175             updateDownArrowMargin();
    176         }
    177 
    178         private void updateDownArrowMargin() {
    179             LayoutParams params = (LayoutParams) mEndSpacer.getLayoutParams();
    180             params.setMarginStart(mContext.getResources().getDimensionPixelSize(
    181                     R.dimen.qs_expand_margin));
    182             mEndSpacer.setLayoutParams(params);
    183         }
    184 
    185         @Override
    186         public void setListening(boolean listening) {
    187             if (mListening == listening) return;
    188             mListening = listening;
    189             for (TileRecord record : mRecords) {
    190                 record.tile.setListening(this, mListening);
    191             }
    192         }
    193 
    194         @Override
    195         public void addTile(TileRecord tile) {
    196             addView(tile.tileView, getChildCount() - 1 /* Leave icon at end */,
    197                     generateLayoutParams());
    198             // Add a spacer.
    199             addView(new Space(mContext), getChildCount() - 1 /* Leave icon at end */,
    200                     generateSpaceParams());
    201             mRecords.add(tile);
    202             tile.tile.setListening(this, mListening);
    203         }
    204 
    205         private LayoutParams generateSpaceParams() {
    206             int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
    207             LayoutParams lp = new LayoutParams(0, size);
    208             lp.weight = 1;
    209             lp.gravity = Gravity.CENTER;
    210             return lp;
    211         }
    212 
    213         private LayoutParams generateLayoutParams() {
    214             int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
    215             LayoutParams lp = new LayoutParams(size, size);
    216             lp.gravity = Gravity.CENTER;
    217             return lp;
    218         }
    219 
    220         @Override
    221         public void removeTile(TileRecord tile) {
    222             int childIndex = getChildIndex(tile.tileView);
    223             // Remove the tile.
    224             removeViewAt(childIndex);
    225             // Remove its spacer as well.
    226             removeViewAt(childIndex);
    227             mRecords.remove(tile);
    228             tile.tile.setListening(this, false);
    229         }
    230 
    231         private int getChildIndex(QSTileBaseView tileView) {
    232             final int N = getChildCount();
    233             for (int i = 0; i < N; i++) {
    234                 if (getChildAt(i) == tileView) {
    235                     return i;
    236                 }
    237             }
    238             return -1;
    239         }
    240 
    241         @Override
    242         public int getOffsetTop(TileRecord tile) {
    243             return 0;
    244         }
    245 
    246         @Override
    247         public boolean updateResources() {
    248             // No resources here.
    249             return false;
    250         }
    251 
    252         @Override
    253         public boolean hasOverlappingRendering() {
    254             return false;
    255         }
    256 
    257         @Override
    258         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    259             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    260             if (mRecords != null && mRecords.size() > 0) {
    261                 View previousView = this;
    262                 for (TileRecord record : mRecords) {
    263                     if (record.tileView.getVisibility() == GONE) continue;
    264                     previousView = record.tileView.updateAccessibilityOrder(previousView);
    265                 }
    266                 mRecords.get(0).tileView.setAccessibilityTraversalAfter(
    267                         R.id.alarm_status_collapsed);
    268                 mRecords.get(mRecords.size() - 1).tileView.setAccessibilityTraversalBefore(
    269                         R.id.expand_indicator);
    270             }
    271         }
    272     }
    273 }
    274