diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java index f1b7eeca5c07b..ca1b48901c9de 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java @@ -261,6 +261,12 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { return mPages.get(0).mColumns; } + public int getNumVisibleTiles() { + if (mPages.size() == 0) return 0; + TilePage currentPage = mPages.get(getCurrentItem()); + return currentPage.mRecords.size(); + } + public void startTileReveal(Set tileSpecs, final Runnable postAnimation) { if (tileSpecs.isEmpty() || mPages.size() < 2 || getScrollX() != 0 || !beginFakeDrag()) { // Do not start the reveal animation unless there are tiles to animate, multiple diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java index 2a4bb607673e7..f6073671dd60e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java @@ -169,6 +169,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha QSTileLayout tileLayout = mQsPanel.getTileLayout(); mAllViews.add((View) tileLayout); int height = mQs.getView() != null ? mQs.getView().getMeasuredHeight() : 0; + int width = mQs.getView() != null ? mQs.getView().getMeasuredWidth() : 0; int heightDiff = height - mQs.getHeader().getBottom() + mQs.getHeader().getPaddingBottom(); firstPageBuilder.addFloat(tileLayout, "translationY", heightDiff, 0); @@ -181,7 +182,9 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha } final View tileIcon = tileView.getIcon().getIconView(); View view = mQs.getView(); - if (count < mNumQuickTiles && mAllowFancy) { + + // This case: less tiles to animate in small displays. + if (count < mQuickQsPanel.getTileLayout().getNumVisibleTiles() && mAllowFancy) { // Quick tiles. QSTileView quickTileView = mQuickQsPanel.getTileView(tile); if (quickTileView == null) continue; @@ -192,18 +195,26 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha final int xDiff = loc2[0] - loc1[0]; final int yDiff = loc2[1] - loc1[1]; lastXDiff = loc1[0] - lastX; - // Move the quick tile right from its location to the new one. - translationXBuilder.addFloat(quickTileView, "translationX", 0, xDiff); - translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff); - // Counteract the parent translation on the tile. So we have a static base to - // animate the label position off from. - //firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0); + if (count < tileLayout.getNumVisibleTiles()) { + // Move the quick tile right from its location to the new one. + translationXBuilder.addFloat(quickTileView, "translationX", 0, xDiff); + translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff); - // Move the real tile from the quick tile position to its final - // location. - translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0); - translationYBuilder.addFloat(tileView, "translationY", -yDiff, 0); + // Counteract the parent translation on the tile. So we have a static base to + // animate the label position off from. + //firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0); + + // Move the real tile from the quick tile position to its final + // location. + translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0); + translationYBuilder.addFloat(tileView, "translationY", -yDiff, 0); + + } else { // These tiles disappear when expanding + firstPageBuilder.addFloat(quickTileView, "alpha", 1, 0); + translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff); + translationXBuilder.addFloat(quickTileView, "translationX", 0, xDiff + width); + } mQuickQsViews.add(tileView.getIconWithBackground()); mAllViews.add(tileView.getIcon()); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 8697015742378..762fd75f48dc3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -665,5 +665,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne void setListening(boolean listening); default void setExpansion(float expansion) {} + + int getNumVisibleTiles(); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index 1c50f797e1a79..556786a16cafa 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -18,18 +18,17 @@ package com.android.systemui.qs; import android.content.Context; import android.content.res.Configuration; +import android.graphics.Rect; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.widget.LinearLayout; -import android.widget.Space; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTile.SignalState; import com.android.systemui.plugins.qs.QSTile.State; -import com.android.systemui.plugins.qs.QSTileView; import com.android.systemui.qs.customize.QSCustomizer; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; @@ -43,6 +42,7 @@ import java.util.Collection; public class QuickQSPanel extends QSPanel { public static final String NUM_QUICK_TILES = "sysui_qqs_count"; + private static final String TAG = "QuickQSPanel"; private boolean mDisabledByPolicy; private static int mDefaultMaxTiles; @@ -178,121 +178,95 @@ public class QuickQSPanel extends QSPanel { super.setVisibility(visibility); } - private static class HeaderTileLayout extends LinearLayout implements QSTileLayout { + private static class HeaderTileLayout extends TileLayout { - protected final ArrayList mRecords = new ArrayList<>(); private boolean mListening; - /** Size of the QS tile (width & height). */ - private int mTileDimensionSize; public HeaderTileLayout(Context context) { super(context); setClipChildren(false); setClipToPadding(false); - - mTileDimensionSize = mContext.getResources().getDimensionPixelSize( - R.dimen.qs_quick_tile_size); - updateLayoutParams(); } @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - updateLayoutParams(); + updateResources(); + } + + @Override + public void onFinishInflate(){ + updateResources(); } private void updateLayoutParams() { - setGravity(Gravity.CENTER); int width = getResources().getDimensionPixelSize(R.dimen.qs_quick_layout_width); - LayoutParams lp = new LayoutParams(width, LayoutParams.MATCH_PARENT); + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(width, LayoutParams.MATCH_PARENT); lp.gravity = Gravity.CENTER_HORIZONTAL; setLayoutParams(lp); } - /** - * Returns {@link LayoutParams} based on the given {@code spaceWidth}. If the width is 0, - * then we're going to have the space expand to take up as much space as possible. If the - * width is non-zero, we want the inter-tile spacers to be fixed. - */ - private LayoutParams generateSpaceLayoutParams() { - LayoutParams lp = new LayoutParams(0, mTileDimensionSize); - lp.weight = 1; - lp.gravity = Gravity.CENTER; - return lp; - } - - @Override - public void setListening(boolean listening) { - if (mListening == listening) return; - mListening = listening; - for (TileRecord record : mRecords) { - record.tile.setListening(this, mListening); - } - } - - @Override - public void addTile(TileRecord tile) { - if (getChildCount() != 0) { - addView(new Space(mContext), getChildCount(), generateSpaceLayoutParams()); - } - - addView(tile.tileView, getChildCount(), generateTileLayoutParams()); - mRecords.add(tile); - tile.tile.setListening(this, mListening); - } - private LayoutParams generateTileLayoutParams() { - LayoutParams lp = new LayoutParams(mTileDimensionSize, mTileDimensionSize); - lp.gravity = Gravity.CENTER; + LayoutParams lp = new LayoutParams(mCellWidth, mCellHeight); return lp; } @Override - public void removeTile(TileRecord tile) { - int childIndex = getChildIndex(tile.tileView); - // Remove the tile. - removeViewAt(childIndex); - if (getChildCount() != 0) { - // Remove its spacer as well. - removeViewAt(childIndex); - } - mRecords.remove(tile); - tile.tile.setListening(this, false); - } - - private int getChildIndex(QSTileView tileView) { - final int childViewCount = getChildCount(); - for (int i = 0; i < childViewCount; i++) { - if (getChildAt(i) == tileView) { - return i; - } - } - return -1; + protected void addTileView(TileRecord tile) { + addView(tile.tileView, getChildCount(), generateTileLayoutParams()); } @Override - public int getOffsetTop(TileRecord tile) { - return 0; + protected void onLayout(boolean changed, int l, int t, int r, int b) { + // We only care about clipping on the right side + Rect bounds = new Rect(0, 0, r - l, 10000); + setClipBounds(bounds); + + calculateColumns(); + + for (int i = 0; i < mRecords.size(); i++) { + mRecords.get(i).tileView.setVisibility( i < mColumns ? View.VISIBLE : View.GONE); + } + + setAccessibilityOrder(); + layoutTileRecords(mColumns); } @Override public boolean updateResources() { - // No resources here. + mCellWidth = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size); + mCellHeight = mCellWidth; + + updateLayoutParams(); + return false; } - @Override - public boolean hasOverlappingRendering() { - return false; - } + private boolean calculateColumns() { + int prevNumColumns = mColumns; + int maxTiles = mRecords.size(); - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - if (hideOverflowingChildren(widthMeasureSpec)) { - return; // Rely on visibility change to trigger remeasure. + if (maxTiles == 0){ // Early return during setup + mColumns = 0; + return true; } + final int availableWidth = getMeasuredWidth() - getPaddingStart() - getPaddingEnd(); + final int leftoverWithespace = availableWidth - maxTiles * mCellWidth; + final int smallestHorizontalMarginNeeded = leftoverWithespace / (maxTiles - 1); + + if (smallestHorizontalMarginNeeded > 0){ + mCellMarginHorizontal = smallestHorizontalMarginNeeded; + mColumns = maxTiles; + } else{ + mColumns = mCellWidth == 0 ? 1 : + Math.min(maxTiles, availableWidth / mCellWidth ); + mCellMarginHorizontal = (availableWidth - mColumns * mCellWidth) / (mColumns - 1); + } + return mColumns != prevNumColumns; + } + + private void setAccessibilityOrder() { if (mRecords != null && mRecords.size() > 0) { View previousView = this; for (TileRecord record : mRecords) { @@ -306,31 +280,28 @@ public class QuickQSPanel extends QSPanel { } } - /** - * Hide child views that would otherwise be clipped. - * @return {@code true} if any child visibilities have changed. - */ - private boolean hideOverflowingChildren(int widthMeasureSpec) { - if (getChildCount() == 0) { - return false; + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // Measure each QS tile. + for (TileRecord record : mRecords) { + if (record.tileView.getVisibility() == GONE) continue; + record.tileView.measure(exactly(mCellWidth), exactly(mCellHeight)); } - boolean childVisibilityChanged = false; - int widthRemaining = MeasureSpec.getSize(widthMeasureSpec) - - getChildAt(0).getMeasuredWidth() - getPaddingStart() - getPaddingEnd(); - for (int i = 2; i < getChildCount(); i += 2) { - View tileChild = getChildAt(i); - LayoutParams lp = (LayoutParams) tileChild.getLayoutParams(); - // All Space views have 0 width; only tiles contribute to the total width. - widthRemaining = widthRemaining - - tileChild.getMeasuredWidth() - lp.getMarginEnd() - lp.getMarginStart(); - int newVisibility = widthRemaining < 0 ? View.GONE : View.VISIBLE; - if (tileChild.getVisibility() != newVisibility) { - tileChild.setVisibility(newVisibility); - getChildAt(i - 1).setVisibility(newVisibility); // Hide spacer as well. - childVisibilityChanged = true; - } - } - return childVisibilityChanged; + + int height = mCellHeight; + if (height < 0) height = 0; + + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height); + } + + @Override + public int getNumVisibleTiles() { + return mColumns; + } + + @Override + protected int getColumnStart(int column) { + return getPaddingStart() + column * (mCellWidth + mCellMarginHorizontal); } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java index 45d63e0c1359f..c67165ea95a14 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java @@ -56,6 +56,10 @@ public class TileLayout extends ViewGroup implements QSTileLayout { public void addTile(TileRecord tile) { mRecords.add(tile); tile.tile.setListening(this, mListening); + addTileView(tile); + } + + protected void addTileView(TileRecord tile) { addView(tile.tileView); } @@ -120,19 +124,18 @@ public class TileLayout extends ViewGroup implements QSTileLayout { return false; } - private static int exactly(int size) { + protected static int exactly(int size) { return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY); } - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - final int w = getWidth(); + + protected void layoutTileRecords(int numRecords) { final boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL; int row = 0; int column = 0; // Layout each QS tile. - for (int i = 0; i < mRecords.size(); i++, column++) { + for (int i = 0; i < numRecords; i++, column++) { // If we reached the last column available to layout a tile, wrap back to the next row. if (column == mColumns) { column = 0; @@ -147,12 +150,22 @@ public class TileLayout extends ViewGroup implements QSTileLayout { } } + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + layoutTileRecords(mRecords.size()); + } + private int getRowTop(int row) { return row * (mCellHeight + mCellMarginVertical) + mCellMarginTop; } - private int getColumnStart(int column) { + protected int getColumnStart(int column) { return getPaddingStart() + mSidePadding + mCellMarginHorizontal / 2 + column * (mCellWidth + mCellMarginHorizontal); } + + @Override + public int getNumVisibleTiles() { + return mRecords.size(); + } }