sysui: refactor for extensibility.

Extended QSDetail / QSTile to control the behavior with
header / footer.

Bug: 28169547
Change-Id: Ice7d5fc16a0e9080a5c842295abe87bc1e2d71be
(cherry picked from commit dbdcb44b7fa49931fc506535a4cc02c20085bca5)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 0cf7e479..f4b4968 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -46,23 +46,23 @@
     private final SparseArray<View> mDetailViews = new SparseArray<>();
 
     private ViewGroup mDetailContent;
-    private TextView mDetailSettingsButton;
-    private TextView mDetailDoneButton;
+    protected TextView mDetailSettingsButton;
+    protected TextView mDetailDoneButton;
     private QSDetailClipper mClipper;
     private DetailAdapter mDetailAdapter;
     private QSPanel mQsPanel;
 
-    private View mQsDetailHeader;
-    private TextView mQsDetailHeaderTitle;
+    protected View mQsDetailHeader;
+    protected TextView mQsDetailHeaderTitle;
     private Switch mQsDetailHeaderSwitch;
     private ImageView mQsDetailHeaderProgress;
 
-    private QSTileHost mHost;
+    protected QSTileHost mHost;
 
     private boolean mScanState;
     private boolean mClosingDetail;
     private boolean mFullyExpanded;
-    private View mQsDetailHeaderBack;
+    protected View mQsDetailHeaderBack;
     private BaseStatusBarHeader mHeader;
 
     public QSDetail(Context context, @Nullable AttributeSet attrs) {
@@ -139,28 +139,13 @@
         return mClosingDetail;
     }
 
-    private void handleShowingDetail(final QSTile.DetailAdapter adapter, int x, int y) {
+
+
+    public void handleShowingDetail(final QSTile.DetailAdapter adapter, int x, int y) {
         final boolean showingDetail = adapter != null;
         setClickable(showingDetail);
         if (showingDetail) {
-            mQsDetailHeaderTitle.setText(adapter.getTitle());
-            final Boolean toggleState = adapter.getToggleState();
-            if (toggleState == null) {
-                mQsDetailHeaderSwitch.setVisibility(INVISIBLE);
-                mQsDetailHeader.setClickable(false);
-            } else {
-                mQsDetailHeaderSwitch.setVisibility(VISIBLE);
-                mQsDetailHeaderSwitch.setChecked(toggleState);
-                mQsDetailHeader.setClickable(true);
-                mQsDetailHeader.setOnClickListener(new OnClickListener() {
-                    @Override
-                    public void onClick(View v) {
-                        boolean checked = !mQsDetailHeaderSwitch.isChecked();
-                        mQsDetailHeaderSwitch.setChecked(checked);
-                        adapter.setToggleState(checked);
-                    }
-                });
-            }
+            setupDetailHeader(adapter);
         }
 
         boolean visibleDiff = (mDetailAdapter != null) != (adapter != null);
@@ -172,14 +157,7 @@
                     mDetailContent);
             if (detailView == null) throw new IllegalStateException("Must return detail view");
 
-            final Intent settingsIntent = adapter.getSettingsIntent();
-            mDetailSettingsButton.setVisibility(settingsIntent != null ? VISIBLE : GONE);
-            mDetailSettingsButton.setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    mHost.startActivityDismissingKeyguard(settingsIntent);
-                }
-            });
+            setupDetailFooter(adapter);
 
             mDetailContent.removeAllViews();
             mDetailContent.addView(detailView);
@@ -203,6 +181,11 @@
             mQsPanelCallback.onScanStateChanged(false);
         }
         sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+
+        animateDetailVisibleDiff(x, y, visibleDiff, listener);
+    }
+
+    protected void animateDetailVisibleDiff(int x, int y, boolean visibleDiff, AnimatorListener listener) {
         if (visibleDiff) {
             if (mFullyExpanded || mDetailAdapter != null) {
                 setAlpha(1);
@@ -216,6 +199,38 @@
         }
     }
 
+    protected void setupDetailFooter(DetailAdapter adapter) {
+        final Intent settingsIntent = adapter.getSettingsIntent();
+        mDetailSettingsButton.setVisibility(settingsIntent != null ? VISIBLE : GONE);
+        mDetailSettingsButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mHost.startActivityDismissingKeyguard(settingsIntent);
+            }
+        });
+    }
+
+    protected void setupDetailHeader(final DetailAdapter adapter) {
+        mQsDetailHeaderTitle.setText(adapter.getTitle());
+        final Boolean toggleState = adapter.getToggleState();
+        if (toggleState == null) {
+            mQsDetailHeaderSwitch.setVisibility(INVISIBLE);
+            mQsDetailHeader.setClickable(false);
+        } else {
+            mQsDetailHeaderSwitch.setVisibility(VISIBLE);
+            mQsDetailHeaderSwitch.setChecked(toggleState);
+            mQsDetailHeader.setClickable(true);
+            mQsDetailHeader.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    boolean checked = !mQsDetailHeaderSwitch.isChecked();
+                    mQsDetailHeaderSwitch.setChecked(checked);
+                    adapter.setToggleState(checked);
+                }
+            });
+        }
+    }
+
     private void handleToggleStateChanged(boolean state) {
         mQsDetailHeaderSwitch.setChecked(state);
     }
@@ -233,7 +248,7 @@
         }
     }
 
-    private final QSPanel.Callback mQsPanelCallback = new QSPanel.Callback() {
+    protected QSPanel.Callback mQsPanelCallback = new QSPanel.Callback() {
         @Override
         public void onToggleStateChanged(final boolean state) {
             post(new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 2c2f1bd..2cc3086 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -56,7 +56,7 @@
 
     private int mPanelPaddingBottom;
     private int mBrightnessPaddingTop;
-    private boolean mExpanded;
+    protected boolean mExpanded;
     private boolean mListening;
 
     private Callback mCallback;
@@ -228,6 +228,10 @@
         }
     }
 
+    public boolean isExpanded() {
+        return mExpanded;
+    }
+
     public void setListening(boolean listening) {
         if (mListening == listening) return;
         mListening = listening;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 45d8031..38f3098 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -117,6 +117,8 @@
         return null; // optional
     }
 
+    protected DetailAdapter createDetailAdapter() { throw new UnsupportedOperationException(); }
+
     /**
      * Is a startup check whether this device currently supports this tile.
      * Should not be used to conditionally hide tiles.  Only checked on tile
@@ -133,6 +135,17 @@
         Intent getSettingsIntent();
         void setToggleState(boolean state);
         int getMetricsCategory();
+
+        /**
+         * @return the height in px the content of the detail view should take.
+         */
+        default int getDetailViewHeight() { throw new UnsupportedOperationException(); };
+
+        /**
+         * Indicates whether the detail view wants to have its header (back button, title and
+         * toggle) shown.
+         */
+        default boolean hasHeader() { return true; }
     }
 
     // safe to call from any thread
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 2ef3672..042a39b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -42,7 +42,7 @@
     public static final String NUM_QUICK_TILES = "sysui_qqs_count";
 
     private int mMaxTiles;
-    private QSPanel mFullPanel;
+    protected QSPanel mFullPanel;
     private View mHeader;
 
     public QuickQSPanel(Context context, AttributeSet attrs) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 63c85db..bd8029b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -47,7 +47,7 @@
     public BluetoothTile(Host host) {
         super(host);
         mController = host.getBluetoothController();
-        mDetailAdapter = new BluetoothDetailAdapter();
+        mDetailAdapter = (BluetoothDetailAdapter) createDetailAdapter();
     }
 
     @Override
@@ -179,7 +179,12 @@
         }
     };
 
-    private final class BluetoothDetailAdapter implements DetailAdapter, QSDetailItems.Callback {
+    @Override
+    protected DetailAdapter createDetailAdapter() {
+        return new BluetoothDetailAdapter();
+    }
+
+    protected class BluetoothDetailAdapter implements DetailAdapter, QSDetailItems.Callback {
         private QSDetailItems mItems;
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index c72bbf3..db84f6a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -45,7 +45,7 @@
 public class WifiTile extends QSTile<QSTile.SignalState> {
     private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS);
 
-    private final NetworkController mController;
+    protected final NetworkController mController;
     private final AccessPointController mWifiController;
     private final WifiDetailAdapter mDetailAdapter;
     private final QSTile.SignalState mStateBeforeClick = newTileState();
@@ -56,7 +56,7 @@
         super(host);
         mController = host.getNetworkController();
         mWifiController = mController.getAccessPointController();
-        mDetailAdapter = new WifiDetailAdapter();
+        mDetailAdapter = (WifiDetailAdapter) createDetailAdapter();
     }
 
     @Override
@@ -88,6 +88,9 @@
     }
 
     @Override
+    protected DetailAdapter createDetailAdapter() { return new WifiDetailAdapter(); }
+
+    @Override
     public QSIconView createTileView(Context context) {
         return new SignalTileView(context);
     }
@@ -246,7 +249,7 @@
         }
     };
 
-    private final class WifiDetailAdapter implements DetailAdapter,
+    protected class WifiDetailAdapter implements DetailAdapter,
             NetworkController.AccessPointController.AccessPointCallback, QSDetailItems.Callback {
 
         private QSDetailItems mItems;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 7e2fa2d..12b8b91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -955,7 +955,7 @@
         onQsExpansionStarted(0);
     }
 
-    private void onQsExpansionStarted(int overscrollAmount) {
+    protected void onQsExpansionStarted(int overscrollAmount) {
         cancelQsAnimation();
         cancelHeightAnimator();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index 4a8d27f..06f107b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -73,7 +73,7 @@
     private boolean mListening;
     private AlarmManager.AlarmClockInfo mNextAlarm;
 
-    private QuickQSPanel mHeaderQsPanel;
+    protected QuickQSPanel mHeaderQsPanel;
     private boolean mShowEmergencyCallsOnly;
     protected MultiUserSwitch mMultiUserSwitch;
     private ImageView mMultiUserAvatar;