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.View; 23 import android.widget.LinearLayout; 24 25 import com.android.internal.logging.UiEventLogger; 26 import com.android.systemui.R; 27 import com.android.systemui.plugins.qs.QSTile; 28 import com.android.systemui.plugins.qs.QSTile.SignalState; 29 import com.android.systemui.plugins.qs.QSTile.State; 30 31 /** 32 * Version of QSPanel that only shows N Quick Tiles in the QS Header. 33 */ 34 public class QuickQSPanel extends QSPanel { 35 36 private static final String TAG = "QuickQSPanel"; 37 // A fallback value for max tiles number when setting via Tuner (parseNumTiles) 38 public static final int TUNER_MAX_TILES_FALLBACK = 6; 39 40 private boolean mDisabledByPolicy; 41 private int mMaxTiles; 42 QuickQSPanel(Context context, AttributeSet attrs)43 public QuickQSPanel(Context context, AttributeSet attrs) { 44 super(context, attrs); 45 mMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_tiles); 46 } 47 48 @Override initialize()49 void initialize() { 50 super.initialize(); 51 if (mHorizontalContentContainer != null) { 52 mHorizontalContentContainer.setClipChildren(false); 53 } 54 } 55 56 @Override getOrCreateTileLayout()57 public TileLayout getOrCreateTileLayout() { 58 return new QQSSideLabelTileLayout(mContext); 59 } 60 61 62 @Override displayMediaMarginsOnMedia()63 protected boolean displayMediaMarginsOnMedia() { 64 // Margins should be on the container to visually center the view 65 return false; 66 } 67 68 @Override mediaNeedsTopMargin()69 protected boolean mediaNeedsTopMargin() { 70 return true; 71 } 72 73 @Override updatePadding()74 protected void updatePadding() { 75 // QS Panel is setting a top padding by default, which we don't need. 76 } 77 78 @Override getDumpableTag()79 protected String getDumpableTag() { 80 return TAG; 81 } 82 83 @Override shouldShowDetail()84 protected boolean shouldShowDetail() { 85 return !mExpanded; 86 } 87 88 @Override drawTile(QSPanelControllerBase.TileRecord r, State state)89 protected void drawTile(QSPanelControllerBase.TileRecord r, State state) { 90 if (state instanceof SignalState) { 91 SignalState copy = new SignalState(); 92 state.copyTo(copy); 93 // No activity shown in the quick panel. 94 copy.activityIn = false; 95 copy.activityOut = false; 96 state = copy; 97 } 98 super.drawTile(r, state); 99 } 100 setMaxTiles(int maxTiles)101 public void setMaxTiles(int maxTiles) { 102 mMaxTiles = maxTiles; 103 } 104 105 @Override onTuningChanged(String key, String newValue)106 public void onTuningChanged(String key, String newValue) { 107 if (QS_SHOW_BRIGHTNESS.equals(key)) { 108 // No Brightness or Tooltip for you! 109 super.onTuningChanged(key, "0"); 110 } 111 } 112 getNumQuickTiles()113 public int getNumQuickTiles() { 114 return mMaxTiles; 115 } 116 117 /** 118 * Parses the String setting into the number of tiles. Defaults to 119 * {@link #TUNER_MAX_TILES_FALLBACK} 120 * 121 * @param numTilesValue value of the setting to parse 122 * @return parsed value of numTilesValue OR {@link #TUNER_MAX_TILES_FALLBACK} on error 123 */ parseNumTiles(String numTilesValue)124 public static int parseNumTiles(String numTilesValue) { 125 try { 126 return Integer.parseInt(numTilesValue); 127 } catch (NumberFormatException e) { 128 // Couldn't read an int from the new setting value. Use default. 129 return TUNER_MAX_TILES_FALLBACK; 130 } 131 } 132 setDisabledByPolicy(boolean disabled)133 void setDisabledByPolicy(boolean disabled) { 134 if (disabled != mDisabledByPolicy) { 135 mDisabledByPolicy = disabled; 136 setVisibility(disabled ? View.GONE : View.VISIBLE); 137 } 138 } 139 140 /** 141 * Sets the visibility of this {@link QuickQSPanel}. This method has no effect when this panel 142 * is disabled by policy through {@link #setDisabledByPolicy(boolean)}, and in this case the 143 * visibility will always be {@link View#GONE}. This method is called externally by 144 * {@link QSAnimator} only. 145 */ 146 @Override setVisibility(int visibility)147 public void setVisibility(int visibility) { 148 if (mDisabledByPolicy) { 149 if (getVisibility() == View.GONE) { 150 return; 151 } 152 visibility = View.GONE; 153 } 154 super.setVisibility(visibility); 155 } 156 157 @Override openPanelEvent()158 protected QSEvent openPanelEvent() { 159 return QSEvent.QQS_PANEL_EXPANDED; 160 } 161 162 @Override closePanelEvent()163 protected QSEvent closePanelEvent() { 164 return QSEvent.QQS_PANEL_COLLAPSED; 165 } 166 167 @Override tileVisibleEvent()168 protected QSEvent tileVisibleEvent() { 169 return QSEvent.QQS_TILE_VISIBLE; 170 } 171 172 static class QQSSideLabelTileLayout extends SideLabelTileLayout { 173 174 private boolean mLastSelected; 175 QQSSideLabelTileLayout(Context context)176 QQSSideLabelTileLayout(Context context) { 177 super(context, null); 178 setClipChildren(false); 179 setClipToPadding(false); 180 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 181 LayoutParams.WRAP_CONTENT); 182 setLayoutParams(lp); 183 setMaxColumns(4); 184 } 185 186 @Override updateResources()187 public boolean updateResources() { 188 mCellHeightResId = R.dimen.qs_quick_tile_size; 189 boolean b = super.updateResources(); 190 mMaxAllowedRows = getResources().getInteger(R.integer.quick_qs_panel_max_rows); 191 return b; 192 } 193 194 @Override onConfigurationChanged(Configuration newConfig)195 protected void onConfigurationChanged(Configuration newConfig) { 196 super.onConfigurationChanged(newConfig); 197 updateResources(); 198 } 199 200 @Override onMeasure(int widthMeasureSpec, int heightMeasureSpec)201 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 202 // Make sure to always use the correct number of rows. As it's determined by the 203 // columns, just use as many as needed. 204 updateMaxRows(10000, mRecords.size()); 205 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 206 } 207 208 @Override setListening(boolean listening, UiEventLogger uiEventLogger)209 public void setListening(boolean listening, UiEventLogger uiEventLogger) { 210 boolean startedListening = !mListening && listening; 211 super.setListening(listening, uiEventLogger); 212 if (startedListening) { 213 // getNumVisibleTiles() <= mRecords.size() 214 for (int i = 0; i < getNumVisibleTiles(); i++) { 215 QSTile tile = mRecords.get(i).tile; 216 uiEventLogger.logWithInstanceId(QSEvent.QQS_TILE_VISIBLE, 0, 217 tile.getMetricsSpec(), tile.getInstanceId()); 218 } 219 } 220 } 221 222 @Override setExpansion(float expansion, float proposedTranslation)223 public void setExpansion(float expansion, float proposedTranslation) { 224 if (expansion > 0f && expansion < 1f) { 225 return; 226 } 227 // The cases we must set select for marquee when QQS/QS collapsed, and QS full expanded. 228 // Expansion == 0f is when QQS is fully showing (as opposed to 1f, which is QS). At this 229 // point we want them to be selected so the tiles will marquee (but not at other points 230 // of expansion. 231 boolean selected = (expansion == 1f || proposedTranslation < 0f); 232 if (mLastSelected == selected) { 233 return; 234 } 235 // We set it as not important while we change this, so setting each tile as selected 236 // will not cause them to announce themselves until the user has actually selected the 237 // item. 238 setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); 239 for (int i = 0; i < getChildCount(); i++) { 240 getChildAt(i).setSelected(selected); 241 } 242 setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); 243 mLastSelected = selected; 244 } 245 } 246 } 247