diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java index f07e8fccd894f..cf96457ce09c6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java @@ -31,6 +31,10 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { private View mDecorGroup; private PageListener mPageListener; + private int mPosition; + private boolean mOffPage; + private boolean mListening; + public PagedTileLayout(Context context, AttributeSet attrs) { super(context, attrs); setAdapter(mAdapter); @@ -48,6 +52,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { if (mPageIndicator == null) return; + setCurrentPage(position, positionOffset != 0); mPageIndicator.setLocation(position + positionOffset); if (mPageListener != null) { mPageListener.onPageChanged(positionOffsetPixels == 0 && @@ -77,6 +82,52 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { super.setCurrentItem(item, smoothScroll); } + @Override + public void setListening(boolean listening) { + if (mListening == listening) return; + mListening = listening; + if (mListening) { + mPages.get(mPosition).setListening(listening); + if (mOffPage) { + mPages.get(mPosition + 1).setListening(listening); + } + } else { + // Make sure no pages are listening. + for (int i = 0; i < mPages.size(); i++) { + mPages.get(i).setListening(false); + } + } + } + + /** + * Sets individual pages to listening or not. If offPage it will set + * the next page after position to listening as well since we are in between + * pages. + */ + private void setCurrentPage(int position, boolean offPage) { + if (mPosition == position && mOffPage == offPage) return; + if (mListening) { + if (mPosition != position) { + // Clear out the last pages from listening. + mPages.get(mPosition).setListening(false); + if (mOffPage) { + mPages.get(mPosition + 1).setListening(false); + } + // Set the new pages to listening + mPages.get(position).setListening(true); + if (offPage) { + mPages.get(position + 1).setListening(true); + } + } else if (mOffPage != offPage) { + // Whether we are showing position + 1 has changed. + mPages.get(mPosition + 1).setListening(offPage); + } + } + // Save the current state. + mPosition = position; + mOffPage = offPage; + } + @Override public boolean hasOverlappingRendering() { return false; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java index ef7556267e0cd..8d6e17e2622b8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java @@ -60,6 +60,7 @@ public class QSContainer extends FrameLayout { private QSAnimator mQSAnimator; private QSCustomizer mQSCustomizer; private NotificationPanelView mPanelView; + private boolean mListening; public QSContainer(Context context, AttributeSet attrs) { super(context, attrs); @@ -209,6 +210,7 @@ public class QSContainer extends FrameLayout { public void setExpanded(boolean expanded) { if (DEBUG) Log.d(TAG, "setExpanded " + expanded); mQsExpanded = expanded; + mQSPanel.setListening(mListening && mQsExpanded); updateQsState(); } @@ -227,8 +229,9 @@ public class QSContainer extends FrameLayout { public void setListening(boolean listening) { if (DEBUG) Log.d(TAG, "setListening " + listening); - mQSPanel.setListening(listening); + mListening = listening; mHeader.setListening(listening); + mQSPanel.setListening(mListening && mQsExpanded); } public void setQsExpansion(float expansion, float headerTranslation) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 12113548a9826..8148844416bf2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -57,7 +57,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback { private int mPanelPaddingBottom; private int mBrightnessPaddingTop; private boolean mExpanded; - private boolean mListening; + protected boolean mListening; private Callback mCallback; private BrightnessController mBrightnessController; @@ -102,6 +102,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback { protected void setupTileLayout() { mTileLayout = (QSTileLayout) LayoutInflater.from(mContext).inflate( R.layout.qs_paged_tile_layout, this, false); + mTileLayout.setListening(mListening); addView((View) mTileLayout); } @@ -228,8 +229,8 @@ public class QSPanel extends LinearLayout implements Tunable, Callback { public void setListening(boolean listening) { if (mListening == listening) return; mListening = listening; - for (TileRecord r : mRecords) { - r.tile.setListening(mListening); + if (mTileLayout != null) { + mTileLayout.setListening(listening); } mFooter.setListening(mListening); if (mListening) { @@ -341,7 +342,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback { } }; r.tileView.init(click, longClick); - r.tile.setListening(mListening); callback.onStateChanged(r.tile.getState()); r.tile.refreshState(); mRecords.add(r); @@ -531,5 +531,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback { void removeTile(TileRecord tile); int getOffsetTop(TileRecord tile); boolean updateResources(); + + void setListening(boolean listening); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java index 0cc30a8642eae..8d9f23fb9242a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java @@ -24,6 +24,7 @@ import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; import android.view.View; @@ -63,7 +64,7 @@ import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; * handleUpdateState. Callbacks affecting state should use refreshState to trigger another * state update pass on tile looper. */ -public abstract class QSTile implements Listenable { +public abstract class QSTile { protected final String TAG = "Tile." + getClass().getSimpleName(); protected static final boolean DEBUG = Log.isLoggable("Tile", Log.DEBUG); @@ -71,6 +72,7 @@ public abstract class QSTile implements Listenable { protected final Context mContext; protected final H mHandler; protected final Handler mUiHandler = new Handler(Looper.getMainLooper()); + private final ArraySet mListeners = new ArraySet<>(); private final ArrayList mCallbacks = new ArrayList<>(); protected TState mState = newTileState(); @@ -97,6 +99,24 @@ public abstract class QSTile implements Listenable { mHandler = new H(host.getLooper()); } + /** + * Adds or removes a listening client for the tile. If the tile has one or more + * listening client it will go into the listening state. + */ + public void setListening(Object listener, boolean listening) { + if (listening) { + if (mListeners.add(listener) && mListeners.size() == 1) { + if (DEBUG) Log.d(TAG, "setListening " + true); + mHandler.obtainMessage(H.SET_LISTENING, 1, 0).sendToTarget(); + } + } else { + if (mListeners.remove(listener) && mListeners.size() == 0) { + if (DEBUG) Log.d(TAG, "setListening " + false); + mHandler.obtainMessage(H.SET_LISTENING, 0, 0).sendToTarget(); + } + } + } + public String getTileSpec() { return mTileSpec; } @@ -279,6 +299,8 @@ public abstract class QSTile implements Listenable { handleRefreshState(null); } + protected abstract void setListening(boolean listening); + protected void handleDestroy() { setListening(false); mCallbacks.clear(); @@ -312,6 +334,7 @@ public abstract class QSTile implements Listenable { private static final int DESTROY = 10; private static final int CLEAR_STATE = 11; private static final int REMOVE_CALLBACKS = 12; + private static final int SET_LISTENING = 13; private H(Looper looper) { super(looper); @@ -364,6 +387,9 @@ public abstract class QSTile implements Listenable { } else if (msg.what == CLEAR_STATE) { name = "handleClearState"; handleClearState(); + } else if (msg.what == SET_LISTENING) { + name = "setListening"; + setListening(msg.arg1 != 0); } else { throw new IllegalArgumentException("Unknown msg: " + msg.what); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index 9adcfbf48a92a..2a0e6b3bea431 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -55,6 +55,7 @@ public class QuickQSPanel extends QSPanel { removeView((View) mTileLayout); } mTileLayout = new HeaderTileLayout(context); + mTileLayout.setListening(mListening); addView((View) mTileLayout, 1 /* Between brightness and footer */); } @@ -146,6 +147,7 @@ public class QuickQSPanel extends QSPanel { private static class HeaderTileLayout extends LinearLayout implements QSTileLayout { protected final ArrayList mRecords = new ArrayList<>(); + private boolean mListening; public HeaderTileLayout(Context context) { super(context); @@ -155,6 +157,15 @@ public class QuickQSPanel extends QSPanel { setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); } + @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) { @@ -163,6 +174,7 @@ public class QuickQSPanel extends QSPanel { } addView(tile.tileView, getChildCount(), generateLayoutParams()); mRecords.add(tile); + tile.tile.setListening(this, mListening); } private LayoutParams generateSpaceParams() { @@ -190,6 +202,7 @@ public class QuickQSPanel extends QSPanel { removeViewAt(childIndex); } mRecords.remove(tile); + tile.tile.setListening(this, false); } private int getChildIndex(QSTileBaseView tileView) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java index a578e6c9cb9e5..a5a1eaaf6662c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java @@ -25,6 +25,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout { protected final ArrayList mRecords = new ArrayList<>(); private int mCellMarginTop; + private boolean mListening; public TileLayout(Context context) { this(context, null); @@ -41,18 +42,32 @@ public class TileLayout extends ViewGroup implements QSTileLayout { return getTop(); } + @Override + public void setListening(boolean listening) { + if (mListening == listening) return; + mListening = listening; + for (TileRecord record : mRecords) { + record.tile.setListening(this, mListening); + } + } + public void addTile(TileRecord tile) { mRecords.add(tile); + tile.tile.setListening(this, mListening); addView(tile.tileView); } @Override public void removeTile(TileRecord tile) { mRecords.remove(tile); + tile.tile.setListening(this, false); removeView(tile.tileView); } public void removeAllViews() { + for (TileRecord record : mRecords) { + record.tile.setListening(this, false); + } mRecords.clear(); super.removeAllViews(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java index fb76918c644de..8ec6a2f66e1ae 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java @@ -66,10 +66,10 @@ public class TileQueryHelper { if (tile == null || !tile.isAvailable()) { continue; } - tile.setListening(true); + tile.setListening(this, true); tile.clearState(); tile.refreshState(); - tile.setListening(false); + tile.setListening(this, false); qsHandler.post(new Runnable() { @Override public void run() {