QS: Introduce bluetooth control panel.

- Factor out common detail item panel view, share with Wifi.
- Add an empty state (large icon + text)
- Implement connect / disconnect for supported BT profiles.
- Wire up "scanning" state, but still waiting on asset.
- Add BT controller info to dump.

Bug:16235253
Change-Id: Icf854cafba962fe4b63767d7206e309d80b7b87b
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
new file mode 100644
index 0000000..24c1378
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+
+/**
+ * Quick settings common detail view with line items.
+ */
+public class QSDetailItems extends FrameLayout {
+    private static final String TAG = "QSDetailItems";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final Context mContext;
+    private final H mHandler = new H();
+
+    private String mTag;
+    private Callback mCallback;
+    private boolean mItemsVisible = true;
+    private LinearLayout mItems;
+    private View mEmpty;
+    private TextView mEmptyText;
+    private ImageView mEmptyIcon;
+
+    public QSDetailItems(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mContext = context;
+        mTag = TAG;
+    }
+
+    public static QSDetailItems convertOrInflate(Context context, View convert, ViewGroup parent) {
+        if (convert instanceof QSDetailItems) {
+            return (QSDetailItems) convert;
+        }
+        return (QSDetailItems) LayoutInflater.from(context).inflate(R.layout.qs_detail_items,
+                parent, false);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mItems = (LinearLayout) findViewById(android.R.id.list);
+        mItems.setVisibility(GONE);
+        mEmpty = findViewById(android.R.id.empty);
+        mEmpty.setVisibility(GONE);
+        mEmptyText = (TextView) mEmpty.findViewById(android.R.id.title);
+        mEmptyIcon = (ImageView) mEmpty.findViewById(android.R.id.icon);
+    }
+
+    public void setTagSuffix(String suffix) {
+        mTag = TAG + "." + suffix;
+    }
+
+    public void setEmptyState(int icon, int text) {
+        mEmptyIcon.setImageResource(icon);
+        mEmptyText.setText(text);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        if (DEBUG) Log.d(mTag, "onAttachedToWindow");
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        if (DEBUG) Log.d(mTag, "onDetachedFromWindow");
+        mCallback = null;
+    }
+
+    public void setCallback(Callback callback) {
+        mHandler.removeMessages(H.SET_CALLBACK);
+        mHandler.obtainMessage(H.SET_CALLBACK, callback).sendToTarget();
+    }
+
+    public void setItems(Item[] items) {
+        mHandler.removeMessages(H.SET_ITEMS);
+        mHandler.obtainMessage(H.SET_ITEMS, items).sendToTarget();
+    }
+
+    public void setItemsVisible(boolean visible) {
+        mHandler.removeMessages(H.SET_ITEMS_VISIBLE);
+        mHandler.obtainMessage(H.SET_ITEMS_VISIBLE, visible ? 1 : 0, 0).sendToTarget();
+    }
+
+    private void handleSetCallback(Callback callback) {
+        mCallback = callback;
+    }
+
+    private void handleSetItems(Item[] items) {
+        final int itemCount = items != null ? items.length : 0;
+        mEmpty.setVisibility(itemCount == 0 ? VISIBLE : GONE);
+        mItems.setVisibility(itemCount == 0 ? GONE : VISIBLE);
+        for (int i = mItems.getChildCount() - 1; i >= itemCount; i--) {
+            mItems.removeViewAt(i);
+        }
+        for (int i = 0; i < itemCount; i++) {
+            bind(items[i], mItems.getChildAt(i));
+        }
+    }
+
+    private void handleSetItemsVisible(boolean visible) {
+        if (mItemsVisible == visible) return;
+        mItemsVisible = visible;
+        for (int i = 0; i < mItems.getChildCount(); i++) {
+            mItems.getChildAt(i).setVisibility(mItemsVisible ? VISIBLE : INVISIBLE);
+        }
+    }
+
+    private void bind(final Item item, View view) {
+        if (view == null) {
+            view = LayoutInflater.from(mContext).inflate(R.layout.qs_detail_item, this, false);
+            mItems.addView(view);
+        }
+        view.setVisibility(mItemsVisible ? VISIBLE : INVISIBLE);
+        final ImageView iv = (ImageView) view.findViewById(android.R.id.icon);
+        iv.setImageResource(item.icon);
+        final TextView title = (TextView) view.findViewById(android.R.id.title);
+        title.setText(item.line1);
+        final TextView summary = (TextView) view.findViewById(android.R.id.summary);
+        final boolean twoLines = !TextUtils.isEmpty(item.line2);
+        summary.setVisibility(twoLines ? VISIBLE : GONE);
+        summary.setText(twoLines ? item.line2 : null);
+        view.setMinimumHeight(mContext.getResources() .getDimensionPixelSize(
+                twoLines ? R.dimen.qs_detail_item_height_twoline : R.dimen.qs_detail_item_height));
+        view.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mCallback != null) {
+                    mCallback.onDetailItemClick(item);
+                }
+            }
+        });
+        final ImageView disconnect = (ImageView) view.findViewById(android.R.id.icon2);
+        disconnect.setVisibility(item.canDisconnect ? VISIBLE : GONE);
+        disconnect.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mCallback != null) {
+                    mCallback.onDetailItemDisconnect(item);
+                }
+            }
+        });
+    }
+
+    private class H extends Handler {
+        private static final int SET_ITEMS = 1;
+        private static final int SET_CALLBACK = 2;
+        private static final int SET_ITEMS_VISIBLE = 3;
+
+        public H() {
+            super(Looper.getMainLooper());
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == SET_ITEMS) {
+                handleSetItems((Item[]) msg.obj);
+            } else if (msg.what == SET_CALLBACK) {
+                handleSetCallback((QSDetailItems.Callback) msg.obj);
+            } else if (msg.what == SET_ITEMS_VISIBLE) {
+                handleSetItemsVisible(msg.arg1 != 0);
+            }
+        }
+    }
+
+    public static class Item {
+        public int icon;
+        public String line1;
+        public String line2;
+        public Object tag;
+        public boolean canDisconnect;
+    }
+
+    public interface Callback {
+        void onDetailItemClick(Item item);
+        void onDetailItemDisconnect(Item item);
+    }
+}