New quick settings implementation.

Bug:14133785
Change-Id: I7f57f8e7ebcc3e1a06fa5204f477470f14299e1f
diff --git a/packages/SystemUI/res/drawable/ic_qs_airplane.xml b/packages/SystemUI/res/drawable/ic_qs_airplane.xml
new file mode 100644
index 0000000..ffe571f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_airplane.xml
@@ -0,0 +1,31 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M10.2,9.0"/>
+    <path
+        android:fill="#FF000000"
+        android:pathData="M21.0,16.0l0.0,-2.0l-8.0,-5.0L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5L10.0,9.0l-8.0,5.0l0.0,2.0l8.0,-2.5L10.0,19.0l-2.0,1.5L8.0,22.0l3.5,-1.0l3.5,1.0l0.0,-1.5L13.0,19.0l0.0,-5.5L21.0,16.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
new file mode 100644
index 0000000..22d0dcf
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M17.7,7.7L12.0,2.0l-1.0,0.0l0.0,7.6L6.4,5.0L5.0,6.4l5.6,5.6L5.0,17.6L6.4,19.0l4.6,-4.6L11.0,22.0l1.0,0.0l5.7,-5.7L13.4,12.0L17.7,7.7zM13.0,5.8l1.9,1.9L13.0,9.6L13.0,5.8zM14.9,16.3L13.0,18.2l0.0,-3.8L14.9,16.3z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bugreport.xml b/packages/SystemUI/res/drawable/ic_qs_bugreport.xml
new file mode 100644
index 0000000..5057390
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_bugreport.xml
@@ -0,0 +1,31 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M19.0,10.0c0.0,-2.3 -1.15,-4.35 -2.9,-5.65l2.101,-2.1L17.4,1.4L15.1,3.7C14.15,3.3 13.1,3.0 12.0,3.0S9.85,3.3 8.9,3.75L6.6,1.45L5.8,2.3L7.9,4.4C6.15,5.65 5.0,7.7 5.0,10.0l0.0,1.0l14.0,0.0L19.0,10.0zM9.0,9.0C8.45,9.0 8.0,8.55 8.0,8.0s0.45,-1.0 1.0,-1.0s1.0,0.45 1.0,1.0S9.55,9.0 9.0,9.0zM15.0,9.0c-0.55,0.0 -1.0,-0.45 -1.0,-1.0s0.45,-1.0 1.0,-1.0s1.0,0.45 1.0,1.0S15.55,9.0 15.0,9.0z"/>
+    <path
+        android:fill="#FF000000"
+        android:pathData="M18.984,16.299C18.989,16.199 19.0,16.102 19.0,16.0l0.0,-2.301l2.517,2.268l0.837,-0.929L19.0,12.018L19.0,12.0L5.0,12.0l0.0,0.021l-0.013,-0.014l-3.364,3.031l0.836,0.929L5.0,13.678L5.0,16.0c0.0,0.11 0.012,0.218 0.017,0.327l-0.029,-0.032l-3.364,3.031l0.836,0.929l2.774,-2.499C6.019,20.762 8.757,23.0 12.0,23.0c3.236,0.0 5.971,-2.229 6.762,-5.227l2.755,2.481l0.837,-0.929l-3.365,-3.031L18.984,16.299z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast.xml b/packages/SystemUI/res/drawable/ic_qs_cast.xml
new file mode 100644
index 0000000..6f2840b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_cast.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M21.0,3.0L3.0,3.0C1.9,3.0 1.0,3.9 1.0,5.0l0.0,3.0l2.0,0.0L3.0,5.0l18.0,0.0l0.0,14.0l-7.0,0.0l0.0,2.0l7.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L23.0,5.0C23.0,3.9 22.1,3.0 21.0,3.0zM1.0,18.0l0.0,3.0l3.0,0.0C4.0,19.3 2.7,18.0 1.0,18.0zM1.0,14.0l0.0,2.0c2.8,0.0 5.0,2.2 5.0,5.0l2.0,0.0C8.0,17.1 4.9,14.0 1.0,14.0zM1.0,10.0l0.0,2.0c5.0,0.0 9.0,4.0 9.0,9.0l2.0,0.0C12.0,14.9 7.1,10.0 1.0,10.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_close.xml b/packages/SystemUI/res/drawable/ic_qs_close.xml
new file mode 100644
index 0000000..c2c72c8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_close.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M19.0,6.4l-1.3999996,-1.4000001 -5.6000004,5.6000004 -5.6,-5.6000004 -1.4000001,1.4000001 5.6000004,5.6 -5.6000004,5.6000004 1.4000001,1.3999996 5.6,-5.6000004 5.6000004,5.6000004 1.3999996,-1.3999996 -5.6000004,-5.6000004z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_hotspot.xml b/packages/SystemUI/res/drawable/ic_qs_hotspot.xml
new file mode 100644
index 0000000..965e3c1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_hotspot.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M12.0,11.0c-1.1,0.0 -2.0,0.9 -2.0,2.0c0.0,1.1 0.9,2.0 2.0,2.0c1.1,0.0 2.0,-0.9 2.0,-2.0C14.0,11.9 13.1,11.0 12.0,11.0zM18.0,13.0c0.0,-3.3 -2.7,-6.0 -6.0,-6.0c-3.3,0.0 -6.0,2.7 -6.0,6.0c0.0,2.2 1.2,4.1 3.0,5.2l1.0,-1.7c-1.2,-0.7 -2.0,-2.0 -2.0,-3.4c0.0,-2.2 1.8,-4.0 4.0,-4.0s4.0,1.8 4.0,4.0c0.0,1.5 -0.8,2.8 -2.0,3.4l1.0,1.7C16.8,17.1 18.0,15.2 18.0,13.0zM12.0,3.0C6.5,3.0 2.0,7.5 2.0,13.0c0.0,3.7 2.0,6.9 5.0,8.6l1.0,-1.7c-2.4,-1.4 -4.0,-4.0 -4.0,-6.9c0.0,-4.4 3.6,-8.0 8.0,-8.0s8.0,3.6 8.0,8.0c0.0,3.0 -1.6,5.5 -4.0,6.9l1.0,1.7c3.0,-1.7 5.0,-5.0 5.0,-8.6C22.0,7.5 17.5,3.0 12.0,3.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_invert_colors.xml b/packages/SystemUI/res/drawable/ic_qs_invert_colors.xml
new file mode 100644
index 0000000..7c92052
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_invert_colors.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M18.939,7.244c-5.887,-5.885 -6.214,-6.214 -6.222,-6.222l-0.707,-0.737L5.088,7.207c-2.914,2.915 -3.74,6.629 -2.266,10.19c1.541,3.719 5.312,6.316 9.174,6.317l0.0,0.0c3.861,-0.001 7.636,-2.603 9.179,-6.328C22.646,13.834 21.832,10.138 18.939,7.244zM4.67,16.632c-1.149,-2.776 -0.481,-5.696 1.832,-8.011l5.494,-5.492c0.0,0.002 0.002,0.003 0.003,0.004l0.0,18.582c-0.001,0.0 -0.002,0.0 -0.003,0.0C8.922,21.714 5.91,19.624 4.67,16.632z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location.xml b/packages/SystemUI/res/drawable/ic_qs_location.xml
new file mode 100644
index 0000000..e6e98a0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_location.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M12.0,2.0C8.1,2.0 5.0,5.1 5.0,9.0c0.0,5.2 7.0,13.0 7.0,13.0s7.0,-7.8 7.0,-13.0C19.0,5.1 15.9,2.0 12.0,2.0zM12.0,11.5c-1.4,0.0 -2.5,-1.1 -2.5,-2.5s1.1,-2.5 2.5,-2.5c1.4,0.0 2.5,1.1 2.5,2.5S13.4,11.5 12.0,11.5z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_minus.xml b/packages/SystemUI/res/drawable/ic_qs_minus.xml
new file mode 100644
index 0000000..8323e89
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_minus.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M7.0,11.0l0.0,2.0l10.0,0.0l0.0,-2.0L7.0,11.0zM12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,20.0c-4.4,0.0 -8.0,-3.6 -8.0,-8.0s3.6,-8.0 8.0,-8.0c4.4,0.0 8.0,3.6 8.0,8.0S16.4,20.0 12.0,20.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_plus.xml b/packages/SystemUI/res/drawable/ic_qs_plus.xml
new file mode 100644
index 0000000..84cd72a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_plus.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M13.0,7.0l-2.0,0.0l0.0,4.0L7.0,11.0l0.0,2.0l4.0,0.0l0.0,4.0l2.0,0.0l0.0,-4.0l4.0,0.0l0.0,-2.0l-4.0,0.0L13.0,7.0zM12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,20.0c-4.4,0.0 -8.0,-3.6 -8.0,-8.0s3.6,-8.0 8.0,-8.0c4.4,0.0 8.0,3.6 8.0,8.0S16.4,20.0 12.0,20.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
new file mode 100644
index 0000000..fa6f20c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M3.0,9.0c0.0,0.0 0.0,6.0 0.0,6.0l4.0,0.0l5.0,5.0L12.0,4.0L7.0,9.0L3.0,9.0zM16.5,12.0c0.0,-1.8 -1.0,-3.3 -2.5,-4.0L14.0,16.0C15.5,15.3 16.5,13.8 16.5,12.0zM14.0,3.2l0.0,2.1c2.9,0.9 5.0,3.5 5.0,6.7s-2.1,5.8 -5.0,6.7l0.0,2.1c4.0,-0.9 7.0,-4.5 7.0,-8.8S18.0,4.1 14.0,3.2z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
new file mode 100644
index 0000000..0665196
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M16.5,12.0c0.0,-1.8 -1.0,-3.3 -2.5,-4.0l0.0,2.2l2.5,2.5C16.5,12.4 16.5,12.2 16.5,12.0zM19.0,12.0c0.0,0.9 -0.2,1.8 -0.5,2.6l1.5,1.5c0.7,-1.2 1.0,-2.7 1.0,-4.2c0.0,-4.3 -3.0,-7.9 -7.0,-8.8l0.0,2.1C16.9,6.2 19.0,8.8 19.0,12.0zM4.3,3.0L3.0,4.3L7.7,9.0L3.0,9.0c0.0,0.0 0.0,6.0 0.0,6.0l4.0,0.0l5.0,5.0l0.0,-6.7l4.3,4.3c-0.7,0.5 -1.4,0.9 -2.3,1.2l0.0,2.1c1.4,-0.3 2.6,-0.9 3.7,-1.8l2.0,2.0l1.3,-1.3l-9.0,-9.0L4.3,3.0zM12.0,4.0L9.9,6.1L12.0,8.2L12.0,4.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
new file mode 100644
index 0000000..299a2ef
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation.xml b/packages/SystemUI/res/drawable/ic_qs_rotation.xml
new file mode 100644
index 0000000..18c5922
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_rotation.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M16.5,2.5c3.3,1.5 5.6,4.7 6.0,8.5l1.5,0.0C23.4,4.8 18.3,0.0 12.0,0.0c-0.2,0.0 -0.4,0.0 -0.7,0.0l3.8,3.8L16.5,2.5zM10.2,1.7c-0.6,-0.6 -1.5,-0.6 -2.1,0.0L1.7,8.1c-0.6,0.6 -0.6,1.5 0.0,2.1l12.0,12.0c0.6,0.6 1.5,0.6 2.1,0.0l6.4,-6.4c0.6,-0.6 0.6,-1.5 0.0,-2.1L10.2,1.7zM14.8,21.2l-12.0,-12.0l6.4,-6.4l12.0,12.0L14.8,21.2zM7.5,21.5c-3.3,-1.5 -5.6,-4.7 -6.0,-8.5L0.1,13.0C0.6,19.2 5.7,24.0 12.0,24.0c0.2,0.0 0.4,0.0 0.7,0.0l-3.8,-3.8L7.5,21.5z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_lock.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_lock.xml
new file mode 100644
index 0000000..1068f30
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_rotation_lock.xml
@@ -0,0 +1,34 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M16.5,2.5c3.3,1.5 5.6,4.7 6.0,8.5L24.0,11.0C23.4,4.8 18.3,0.0 12.0,0.0c-0.2,0.0 -0.4,0.0 -0.7,0.0l3.8,3.8L16.5,2.5zM7.5,21.5c-3.3,-1.5 -5.6,-4.7 -6.0,-8.5L0.1,13.0C0.6,19.2 5.7,24.0 12.0,24.0c0.2,0.0 0.4,0.0 0.7,0.0l-3.8,-3.8L7.5,21.5z"/>
+    <path
+        android:pathData="M12.05,7.7c-1.104,0,-2,0.945,-2,2.05v0.5h4v-0.5C14.05,8.646,13.154,7.7,12.05,7.7z"
+        android:fill="#00000000"/>
+    <path
+        android:fill="#FF000000"
+        android:pathData="M15.05,10.25l0.0,-0.5c0.0,-1.656 -1.343,-3.0 -3.0,-3.0c-1.657,0.0 -2.995,1.344 -2.995,3.0l-0.005,0.5c-0.552,0.0 -1.0,0.448 -1.0,1.0l0.0,5.0c0.0,0.553 0.448,1.0 1.0,1.0l6.0,0.0c0.552,0.0 1.0,-0.447 1.0,-1.0l0.0,-5.0C16.05,10.698 15.602,10.25 15.05,10.25zM12.05,14.75c-0.552,0.0 -1.0,-0.447 -1.0,-1.0c0.0,-0.552 0.448,-1.0 1.0,-1.0s1.0,0.448 1.0,1.0C13.05,14.303 12.602,14.75 12.05,14.75zM14.05,10.25l-4.0,0.0l0.0,-0.5c0.0,-1.104 0.896,-2.05 2.0,-2.05c1.104,0.0 2.0,0.945 2.0,2.05L14.05,10.25z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_locked_landscape.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_locked_landscape.xml
new file mode 100644
index 0000000..532a2ed
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_rotation_locked_landscape.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M21.0,5.0L3.0,5.0C1.9,5.0 1.0,5.9 1.0,7.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l18.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L23.0,7.0C23.0,5.9 22.1,5.0 21.0,5.0zM19.0,17.0L5.0,17.0L5.0,7.0l14.0,0.0L19.0,17.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_locked_portrait.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_locked_portrait.xml
new file mode 100644
index 0000000..496bb0e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_rotation_locked_portrait.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M17.0,1.0L7.0,1.0C5.9,1.0 5.0,1.9 5.0,3.0l0.0,18.0c0.0,1.1 0.9,2.0 2.0,2.0l10.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L19.0,3.0C19.0,1.9 18.1,1.0 17.0,1.0zM17.0,19.0L7.0,19.0L7.0,5.0l10.0,0.0L17.0,19.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_zen.xml b/packages/SystemUI/res/drawable/ic_qs_zen.xml
new file mode 100644
index 0000000..059c068
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_zen.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,16.0l0.0,-5.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0zM14.0,9.8l-2.8,3.4L14.0,13.200001L14.0,15.0L9.0,15.0l0.0,-1.8l2.8,-3.4L9.0,9.799999L9.0,8.0l5.0,0.0L14.0,9.8z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/qs_panel_background.xml b/packages/SystemUI/res/drawable/qs_panel_background.xml
new file mode 100644
index 0000000..c324976
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_panel_background.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+        android:insetLeft="@dimen/notification_side_padding"
+        android:insetRight="@dimen/notification_side_padding">
+    <shape>
+        <solid android:color="@color/system_primary_color" />
+        <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" />
+    </shape>
+</inset>
diff --git a/packages/SystemUI/res/layout/flip_settings.xml b/packages/SystemUI/res/layout/flip_settings.xml
deleted file mode 100644
index 28d9625..0000000
--- a/packages/SystemUI/res/layout/flip_settings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<com.android.systemui.statusbar.phone.QuickSettingsContainerView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/quick_settings_container"
-    android:padding="@dimen/notification_side_padding"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:background="#5f000000"
-    android:animateLayoutChanges="true"
-    android:columnCount="@integer/quick_settings_num_columns" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
new file mode 100644
index 0000000..b24d4ad
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<FrameLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/quick_settings_container"
+        android:paddingLeft="@dimen/notification_side_padding"
+        android:paddingRight="@dimen/notification_side_padding"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@drawable/qs_panel_background" >
+    <com.android.systemui.qs.QSPanel
+            android:id="@+id/quick_settings_panel"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/qs_zen_mode_detail.xml b/packages/SystemUI/res/layout/qs_zen_mode_detail.xml
new file mode 100644
index 0000000..2df6d43
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_zen_mode_detail.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<com.android.systemui.qs.tiles.ZenModeDetail xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/system_secondary_color" >
+
+    <com.android.systemui.qs.QSImageView
+        android:id="@android:id/button1"
+        android:layout_width="64dp"
+        android:layout_height="64dp"
+        android:layout_alignParentStart="true"
+        android:padding="@dimen/quick_settings_panel_padding" />
+
+    <Switch
+        android:id="@android:id/checkbox"
+        android:layout_width="wrap_content"
+        android:layout_height="64dp"
+        android:layout_alignParentEnd="true"
+        android:gravity="center"
+        android:padding="@dimen/quick_settings_panel_padding" />
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="match_parent"
+        android:layout_height="64dp"
+        android:layout_toEndOf="@android:id/button1"
+        android:layout_toStartOf="@android:id/checkbox"
+        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
+        android:gravity="center_vertical"
+        android:paddingStart="@dimen/quick_settings_panel_padding"
+        android:text="@string/zen_mode_title" />
+
+    <View
+        android:id="@android:id/custom"
+        android:layout_width="match_parent"
+        android:layout_height="2dp"
+        android:layout_below="@android:id/title"
+        android:background="#888" />
+
+    <ListView
+        android:id="@android:id/content"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_above="@android:id/button2"
+        android:layout_below="@android:id/custom"
+        android:divider="#00000000"
+        android:dividerHeight="0px" />
+
+    <TextView
+        android:id="@android:id/button2"
+        style="@style/QSBorderless"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentEnd="true"
+        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
+        android:padding="@dimen/quick_settings_panel_padding"
+        android:text="@string/quick_settings_more_settings"
+        android:textAllCaps="true" />
+
+</com.android.systemui.qs.tiles.ZenModeDetail>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml b/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml
new file mode 100644
index 0000000..a5c8903
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+
+    <RadioButton
+        android:id="@android:id/checkbox"
+        android:layout_width="32dp"
+        android:layout_height="64dp"
+        android:layout_alignParentStart="true"
+        android:layout_marginStart="@dimen/quick_settings_panel_padding"
+        android:gravity="center" />
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="match_parent"
+        android:layout_height="64dp"
+        android:layout_toEndOf="@android:id/checkbox"
+        android:layout_toStartOf="@android:id/button1"
+        android:ellipsize="end"
+        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
+        android:gravity="center_vertical"
+        android:maxLines="1"
+        android:text="@string/accessibility_back" />
+
+    <com.android.systemui.qs.QSImageView
+        android:id="@android:id/button1"
+        android:layout_width="64dp"
+        android:layout_height="64dp"
+        android:layout_alignParentEnd="true"
+        android:layout_marginEnd="48dp"
+        android:padding="@dimen/quick_settings_panel_padding"
+        android:paddingRight="0px" />
+
+    <com.android.systemui.qs.QSImageView
+        android:id="@android:id/button2"
+        android:layout_width="64dp"
+        android:layout_height="64dp"
+        android:layout_alignParentEnd="true"
+        android:padding="@dimen/quick_settings_panel_padding" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile.xml b/packages/SystemUI/res/layout/quick_settings_tile.xml
deleted file mode 100644
index 911f6a2..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-<com.android.systemui.statusbar.phone.QuickSettingsTileView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="@dimen/quick_settings_cell_height"
-    android:background="@drawable/qs_tile_background" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_alarm.xml b/packages/SystemUI/res/layout/quick_settings_tile_alarm.xml
deleted file mode 100644
index 493c704..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_alarm.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextAppearance.QuickSettings.TileView.AllInOne"
-    android:id="@+id/alarm_textview"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:gravity="center"
-    android:drawableTop="@drawable/ic_qs_alarm_on"
-    />
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_basic.xml b/packages/SystemUI/res/layout/quick_settings_tile_basic.xml
deleted file mode 100644
index 16bf49c..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_basic.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 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.
--->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_gravity="top"
-    android:orientation="vertical">
-    <ImageView
-        android:id="@+id/image"
-        android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
-        android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
-        android:layout_width="@dimen/qs_tile_icon_size"
-        android:layout_height="@dimen/qs_tile_icon_size"
-        android:layout_gravity="top|center_horizontal"
-        android:scaleType="centerInside"
-        />
-    <TextView
-        style="@style/TextAppearance.QuickSettings.TileView"
-        android:id="@+id/text"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top|center_horizontal"
-        android:gravity="top|center_horizontal"
-        />
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml b/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
deleted file mode 100644
index 1f39aef..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 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.
--->
-<LinearLayout
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_gravity="top"
-        android:orientation="vertical">
-    <com.android.systemui.BatteryMeterView
-            android:id="@+id/image"
-            android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
-            android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
-            android:layout_width="22dp"
-            android:layout_height="32dp"
-            android:padding="3dp"
-            android:layout_gravity="top|center_horizontal"
-            systemui:frameColor="@color/qs_batterymeter_frame_color"
-            />
-    <TextView
-            style="@style/TextAppearance.QuickSettings.TileView"
-            android:id="@+id/text"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_gravity="top|center_horizontal"
-            android:gravity="top|center_horizontal"
-            />
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_ime.xml b/packages/SystemUI/res/layout/quick_settings_tile_ime.xml
deleted file mode 100644
index 1a31efa5..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_ime.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextAppearance.QuickSettings.TileView.AllInOne"
-    android:id="@+id/ime_textview"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:gravity="center"
-    android:drawableTop="@drawable/ic_qs_ime"
-    android:text="@string/quick_settings_ime_label"
-    />
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_media.xml b/packages/SystemUI/res/layout/quick_settings_tile_media.xml
deleted file mode 100644
index 355176c6..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_media.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextAppearance.QuickSettings.TileView.AllInOne"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:gravity="center"
-    android:text="@string/quick_settings_media_device_label"
-    android:singleLine="true"
-    />
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_monitoring.xml b/packages/SystemUI/res/layout/quick_settings_tile_monitoring.xml
deleted file mode 100644
index 4fa48eb..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_monitoring.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 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.
--->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_gravity="top"
-    android:orientation="vertical">
-    <ImageView
-        android:id="@+id/image"
-        android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
-        android:layout_marginBottom="@dimen/qs_cawarn_tile_margin_below_icon"
-        android:layout_width="@dimen/qs_tile_icon_size"
-        android:layout_height="@dimen/qs_tile_icon_size"
-        android:layout_gravity="top|center_horizontal"
-        android:scaleType="centerInside"
-        />
-    <TextView
-        style="@style/TextAppearance.QuickSettings.CaCertWarning"
-        android:id="@+id/text"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top|center_horizontal"
-        android:gravity="top|center_horizontal"
-        />
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml b/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
deleted file mode 100644
index 6bf31e0..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-<RelativeLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_gravity="top">
-    <FrameLayout
-        android:id="@+id/rssi_images"
-        android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
-        android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
-        android:layout_width="@dimen/qs_tile_icon_size"
-        android:layout_height="@dimen/qs_tile_icon_size"
-        android:layout_gravity="top|center_horizontal"
-        android:layout_centerHorizontal="true"
-        >
-        <ImageView
-            android:id="@+id/rssi_image"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_centerInParent="true"
-            />
-        <ImageView
-            android:id="@+id/rssi_overlay_image"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_centerInParent="true"
-            />
-    </FrameLayout>
-    <ImageView
-            android:id="@+id/activity_in"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/ic_qs_signal_in"
-            android:layout_toRightOf="@id/rssi_images"
-            android:layout_alignBottom="@id/rssi_images"
-            />
-    <ImageView
-            android:id="@+id/activity_out"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/ic_qs_signal_out"
-            android:layout_toRightOf="@id/rssi_images"
-            android:layout_alignBottom="@id/rssi_images"
-            />
-    <TextView
-        style="@style/TextAppearance.QuickSettings.TileView"
-        android:id="@+id/rssi_textview"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top|center_horizontal"
-        android:gravity="top|center_horizontal"
-        android:text="@string/quick_settings_rssi_label"
-        android:layout_centerHorizontal="true"
-        android:layout_below="@id/rssi_images"
-        android:textAllCaps="@bool/quick_settings_rssi_tile_capitalization"
-        />
-</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_user.xml b/packages/SystemUI/res/layout/quick_settings_tile_user.xml
deleted file mode 100644
index 80fc685..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_user.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <ImageView
-        android:id="@+id/user_imageview"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:src="@drawable/ic_qs_default_user"
-        android:scaleType="centerCrop"
-        />
-    <TextView
-        style="@style/TextAppearance.QuickSettings.TileView.User"
-        android:id="@+id/user_textview"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_horizontal|bottom"
-        android:gravity="center"
-        android:text="@string/quick_settings_user_label"
-        />
-</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml b/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml
deleted file mode 100644
index e61c595..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 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.
--->
-<RelativeLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_gravity="top">
-    <ImageView
-        android:id="@+id/image"
-        android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
-        android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
-        android:layout_width="@dimen/qs_tile_icon_size"
-        android:layout_height="@dimen/qs_tile_icon_size"
-        android:layout_gravity="top|center_horizontal"
-        android:layout_centerHorizontal="true"
-        android:scaleType="centerInside"
-        />
-    <ImageView
-            android:id="@+id/activity_in"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/ic_qs_wifi_in"
-            android:layout_toRightOf="@id/image"
-            android:layout_alignBottom="@id/image"
-            />
-    <ImageView
-            android:id="@+id/activity_out"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/ic_qs_wifi_out"
-            android:layout_toRightOf="@id/image"
-            android:layout_alignBottom="@id/image"
-            />
-    <TextView
-        style="@style/TextAppearance.QuickSettings.TileView"
-        android:id="@+id/text"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top|center_horizontal"
-        android:gravity="top|center_horizontal"
-        android:layout_centerHorizontal="true"
-        android:layout_below="@id/image" 
-        />
-</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index f045da4..2ec9935 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -67,7 +67,7 @@
                 android:layout_height="wrap_content"
                 android:orientation="vertical">
                 <include
-                    layout="@layout/flip_settings"
+                    layout="@layout/qs_panel"
                     android:layout_marginTop="@dimen/status_bar_header_height_expanded"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"/>
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index 7223773..5755029 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -25,7 +25,7 @@
     <integer name="status_bar_recents_bg_gradient_degrees">90</integer>
 
     <!-- The number of columns in the QuickSettings -->
-    <integer name="quick_settings_num_columns">6</integer>
+    <integer name="quick_settings_num_columns">4</integer>
 
     <!-- The maximum number of rows in the QuickSettings -->
     <integer name="quick_settings_max_rows">2</integer>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index fe2224e..6dea81f 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -21,7 +21,7 @@
      for different hardware and product builds. -->
 <resources>
     <!-- The number of columns in the QuickSettings -->
-    <integer name="quick_settings_num_columns">3</integer>
+    <integer name="quick_settings_num_columns">4</integer>
 
     <!-- The maximum number of rows in the QuickSettings -->
     <integer name="quick_settings_max_rows">4</integer>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index c1a4e26..7de1bd0 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -36,6 +36,14 @@
     <color name="batterymeter_charge_color">#FFFFFFFF</color>
     <color name="batterymeter_bolt_color">#FFFFFFFF</color>
     <color name="qs_batterymeter_frame_color">#FF404040</color>
+    <color name="system_primary_color">#ff263238</color>
+    <color name="system_secondary_color">#ff384248</color>
+    <color name="system_accent_color">#ff7fcac3</color>
+    <color name="system_error_color">#fff0592b</color>
+    <color name="quick_settings_tile_icon_enabled">#ffffffff</color>
+    <color name="quick_settings_tile_icon_disabled">#ffcccccc</color>
+    <color name="quick_settings_tile_divider">#ff888888</color>
+    <color name="quick_settings_tile_text">#FFFFFFFF</color>
     <color name="status_bar_clock_color">#FFFFFFFF</color>
     <drawable name="notification_item_background_color">#ff111111</drawable>
     <drawable name="notification_item_background_color_pressed">#ff454545</drawable>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index ab34030..79612e0 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -271,6 +271,10 @@
 
     <dimen name="quick_settings_tmp_scrim_stroke_width">8dp</dimen>
     <dimen name="quick_settings_tmp_scrim_text_size">30dp</dimen>
+    <dimen name="quick_settings_panel_padding">16dp</dimen>
+    <dimen name="quick_settings_tile_icon_outline">2dp</dimen>
+    <dimen name="quick_settings_tile_text_size">12sp</dimen>
+    <dimen name="quick_settings_tile_divider_height">1dp</dimen>
 
     <dimen name="notifications_top_padding">8dp</dimen>
     
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 3d3cdf6..a50a0ac 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -503,9 +503,15 @@
     <!-- QuickSettings: Brightness dialog auto brightness button [CHAR LIMIT=NONE] -->
     <string name="quick_settings_brightness_dialog_auto_brightness_label">AUTO</string>
     <!-- QuickSettings: Label for the toggle that controls whether display inversion is enabled. [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_inversion_label">Color inversion mode</string>
+    <string name="quick_settings_inversion_label">Invert colors</string>
     <!-- QuickSettings: Label for the toggle that controls whether display color correction is enabled. [CHAR LIMIT=NONE] -->
     <string name="quick_settings_color_space_label">Color correction mode</string>
+    <!-- QuickSettings: Control panel: Label for button that navigates to settings. [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_more_settings">More settings</string>
+    <!-- QuickSettings: Tethering. [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_tethering_label">Tethering</string>
+    <!-- QuickSettings: Hotspot. [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_hotspot_label">Hotspot</string>
 
     <!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
     <string name="recents_empty_message">RECENTS</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 4f52870..1273e74 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -180,4 +180,16 @@
     <style name="StatusBarHeader">
         <item name="android:layout_width">match_parent</item>
     </style>
+
+    <style name="QSWhiteTheme" parent="@android:style/Theme.DeviceDefault">
+        <item name="android:colorControlNormal">#ffffffff</item>
+        <item name="android:colorControlActivated">#ffffffff</item>
+    </style>
+
+    <style name="QSAccentTheme" parent="@android:style/Theme.DeviceDefault">
+        <item name="android:colorControlNormal">@color/system_accent_color</item>
+        <item name="android:colorControlActivated">@color/system_accent_color</item>
+    </style>
+
+    <style name="QSBorderless" parent="@android:style/Widget.Quantum.Button.Borderless" />
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/CircularClipper.java b/packages/SystemUI/src/com/android/systemui/qs/CircularClipper.java
new file mode 100644
index 0000000..16ee3b0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/CircularClipper.java
@@ -0,0 +1,74 @@
+/*
+ * 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.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.view.View;
+
+/** Helper for view-level circular clip animations. **/
+public class CircularClipper {
+
+    private final View mTarget;
+
+    private ValueAnimator mAnimator;
+
+    public CircularClipper(View target) {
+        mTarget = target;
+    }
+
+    public void animateCircularClip(int x, int y, boolean in, AnimatorListener listener) {
+        if (mAnimator != null) {
+            mAnimator.cancel();
+        }
+        final int w = mTarget.getWidth() - x;
+        final int h = mTarget.getHeight() - y;
+        int r = (int) Math.ceil(Math.sqrt(x * x + y * y));
+        r = (int) Math.max(r, Math.ceil(Math.sqrt(w * w + y * y)));
+        r = (int) Math.max(r, Math.ceil(Math.sqrt(w * w + h * h)));
+        r = (int) Math.max(r, Math.ceil(Math.sqrt(x * x + h * h)));
+
+        mAnimator = mTarget.createRevealAnimator(x, y, 0, r);
+        mAnimator.removeAllListeners();
+        if (listener != null) {
+            mAnimator.addListener(listener);
+        }
+        if (in) {
+            mAnimator.addListener(mVisibleOnStart);
+            mAnimator.start();
+        } else {
+            mAnimator.addListener(mGoneOnEnd);
+            mAnimator.reverse();
+        }
+    }
+
+    private final AnimatorListenerAdapter mVisibleOnStart = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationStart(Animator animation) {
+            mTarget.setVisibility(View.VISIBLE);
+        }
+    };
+
+    private final AnimatorListenerAdapter mGoneOnEnd = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mTarget.setVisibility(View.GONE);
+        };
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java b/packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java
new file mode 100644
index 0000000..05c8ee3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java
@@ -0,0 +1,79 @@
+/*
+ * 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.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Rect;
+
+/** Canvas that forwards calls to another canvas.  Can be subclassed to transform drawing calls.
+ * Temporary solution to runtime modification of a single drawable shape into two
+ * enabled & disabled versions.  See QSImageView. **/
+public class FilterCanvas extends Canvas {
+    private final Canvas mCanvas;
+
+    public FilterCanvas(Canvas c) {
+        mCanvas = c;
+    }
+
+    @Override
+    public void drawPath(Path path, Paint paint) {
+        mCanvas.drawPath(path, paint);
+    }
+
+    @Override
+    public int getSaveCount() {
+        return mCanvas.getSaveCount();
+    }
+
+    @Override
+    public int save() {
+        return mCanvas.save();
+    }
+
+    @Override
+    public void translate(float dx, float dy) {
+        mCanvas.translate(dx, dy);
+    }
+
+    @Override
+    public boolean clipRect(int left, int top, int right, int bottom) {
+        return mCanvas.clipRect(left, top, right, bottom);
+    }
+
+    @Override
+    public boolean clipRect(Rect rect) {
+        return mCanvas.clipRect(rect);
+    }
+
+    @Override
+    public void concat(Matrix matrix) {
+        mCanvas.concat(matrix);
+    }
+
+    @Override
+    public void restoreToCount(int saveCount) {
+        mCanvas.restoreToCount(saveCount);
+    }
+
+    @Override
+    public void drawRect(Rect r, Paint paint) {
+        mCanvas.drawRect(r, paint);
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java b/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java
new file mode 100644
index 0000000..1e15b9f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java
@@ -0,0 +1,58 @@
+/*
+ * 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.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings.Global;
+
+import com.android.systemui.statusbar.policy.Disposable;
+
+/** Helper for managing a global setting. **/
+public abstract class GlobalSetting extends ContentObserver implements Disposable {
+    private final Context mContext;
+    private final String mSettingName;
+
+    protected abstract void handleValueChanged(int value);
+
+    public GlobalSetting(Context context, Handler handler, String settingName) {
+        super(handler);
+        mContext = context;
+        mSettingName = settingName;
+        mContext.getContentResolver().registerContentObserver(
+                Global.getUriFor(mSettingName), false, this);
+    }
+
+    public int getValue() {
+        return Global.getInt(mContext.getContentResolver(), mSettingName, 0);
+    }
+
+    public void setValue(int value) {
+        Global.putInt(mContext.getContentResolver(), mSettingName, value);
+    }
+
+    @Override
+    public void dispose() {
+        mContext.getContentResolver().unregisterContentObserver(this);
+    }
+
+    @Override
+    public void onChange(boolean selfChange) {
+        handleValueChanged(getValue());
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSImageView.java b/packages/SystemUI/src/com/android/systemui/qs/QSImageView.java
new file mode 100644
index 0000000..ed67560
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSImageView.java
@@ -0,0 +1,102 @@
+/*
+ * 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.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Path;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.VectorDrawable;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+
+/** ImageView that performs runtime modification of vector drawables (using FilterCanvas). **/
+public class QSImageView extends ImageView {
+
+    private final int mOutlineWidth;
+    private final int mColorEnabled;
+    private final int mColorDisabled;
+    private FilterCanvas mFilterCanvas;
+    private Canvas mCanvas;
+    private boolean mEnabledVersion = true;
+    private boolean mFilter;
+
+    public QSImageView(Context context) {
+        this(context, null);
+    }
+
+    public QSImageView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        final Resources res = context.getResources();
+        mOutlineWidth = res.getDimensionPixelSize(R.dimen.quick_settings_tile_icon_outline);
+        mColorEnabled = res.getColor(R.color.quick_settings_tile_icon_enabled);
+        mColorDisabled = res.getColor(R.color.quick_settings_tile_icon_disabled);
+    }
+
+    public void setEnabledVersion(boolean enabledVersion) {
+        mEnabledVersion = enabledVersion;
+        invalidate();
+    }
+
+    @Override
+    public void setImageDrawable(Drawable drawable) {
+        mFilter = drawable instanceof VectorDrawable;
+        super.setImageDrawable(drawable);
+    }
+
+    @Override
+    public void setImageResource(int resId) {
+        setImageDrawable(mContext.getDrawable(resId));
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        if (mFilter) {
+            if (canvas != mCanvas) {
+                mCanvas = canvas;
+                mFilterCanvas = new QSFilterCanvas(canvas);
+            }
+            super.draw(mFilterCanvas);
+        } else {
+            super.draw(canvas);
+        }
+    }
+
+    private class QSFilterCanvas extends FilterCanvas {
+        public QSFilterCanvas(Canvas c) {
+            super(c);
+        }
+
+        @Override
+        public void drawPath(Path path, Paint paint) {
+            if (mEnabledVersion) {
+                paint.setColor(mColorEnabled);
+            } else {
+                paint.setStyle(Style.STROKE);
+                paint.setStrokeJoin(Paint.Join.ROUND);
+                paint.setColor(mColorDisabled);
+                paint.setStrokeWidth(mOutlineWidth);
+            }
+            super.drawPath(path, paint);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
new file mode 100644
index 0000000..afb5483
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -0,0 +1,247 @@
+/*
+ * 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.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.systemui.R;
+
+import java.util.ArrayList;
+
+/** View that represents the quick settings tile panel. **/
+public class QSPanel extends ViewGroup {
+    private static final float TILE_ASPECT = 1.4f;
+    private static final float LARGE_TILE_FACTOR = 1.1f;
+
+    private final Context mContext;
+    private final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
+    private final FrameLayout mDetail;
+    private final CircularClipper mClipper;
+    private final H mHandler = new H();
+
+    private int mColumns;
+    private int mCellWidth;
+    private int mCellHeight;
+    private int mLargeCellWidth;
+    private int mLargeCellHeight;
+
+    private TileRecord mDetailRecord;
+
+    public QSPanel(Context context) {
+        this(context, null);
+    }
+
+    public QSPanel(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mContext = context;
+
+        mDetail = new FrameLayout(mContext);
+        mDetail.setVisibility(GONE);
+        mDetail.setClickable(true);
+        addView(mDetail);
+        mClipper = new CircularClipper(mDetail);
+        updateResources();
+    }
+
+    public void updateResources() {
+        final int columns = Math.max(1,
+                mContext.getResources().getInteger(R.integer.quick_settings_num_columns));
+        if (mColumns != columns) {
+            mColumns = columns;
+            postInvalidate();
+        }
+    }
+
+    public void setExpanded(boolean expanded) {
+        if (!expanded) {
+            showDetail(false /*show*/, mDetailRecord);
+        }
+        for (TileRecord r : mRecords) {
+            r.tile.setShown(expanded);
+        }
+    }
+
+    private void showDetail(boolean show, TileRecord r) {
+        mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0, r).sendToTarget();
+    }
+
+    private void setTileVisibility(View v, boolean visible) {
+        mHandler.obtainMessage(H.SET_TILE_VISIBILITY, visible ? 1 : 0, 0, v).sendToTarget();
+    }
+
+    private void handleSetTileVisibility(View v, boolean visible) {
+        v.setVisibility(visible ? VISIBLE : GONE);
+    }
+
+    public void addTile(final QSTile<?> tile) {
+        final TileRecord r = new TileRecord();
+        r.tile = tile;
+        r.tileView = tile.createTileView(mContext);
+        r.tileView.setVisibility(View.GONE);
+        r.tile.setCallback(new QSTile.Callback() {
+            @Override
+            public void onStateChanged(QSTile.State state) {
+                setTileVisibility(r.tileView, state.visible);
+                r.tileView.onStateChanged(state);
+            }
+            @Override
+            public void onShowDetail(boolean show) {
+                QSPanel.this.showDetail(show, r);
+            }
+        });
+        final View.OnClickListener click = new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                r.tile.click();
+            }
+        };
+        final View.OnClickListener clickSecondary = new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                r.tile.secondaryClick();
+            }
+        };
+        r.tileView.init(click, clickSecondary);
+        mRecords.add(r);
+
+        addView(r.tileView);
+    }
+
+    private void handleShowDetail(TileRecord r, boolean show) {
+        AnimatorListener listener = null;
+        if (show) {
+            if (mDetailRecord != null) return;
+            final View detail = r.tile.createDetailView(mContext, mDetail);
+            if (detail == null) return;
+            mDetailRecord = r;
+            mDetail.removeAllViews();
+            mDetail.bringToFront();
+            mDetail.addView(detail);
+        } else {
+            if (mDetailRecord == null) return;
+            listener = mTeardownDetailWhenDone;
+        }
+        int x = r.tileView.getLeft() + r.tileView.getWidth() / 2;
+        int y = r.tileView.getTop() + r.tileView.getHeight() / 2;
+        mClipper.animateCircularClip(x, y, show, listener);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int width = MeasureSpec.getSize(widthMeasureSpec);
+        mCellWidth = width / mColumns;
+        mCellHeight = (int)(mCellWidth / TILE_ASPECT);
+        mLargeCellWidth = (int)(mCellWidth * LARGE_TILE_FACTOR);
+        mLargeCellHeight = (int)(mCellHeight * LARGE_TILE_FACTOR);
+        int r = 0;
+        int c = 0;
+        int rows = 0;
+        for (TileRecord record : mRecords) {
+            if (record.tileView.getVisibility() == GONE) continue;
+            record.row = r;
+            record.col = c;
+            rows = r + 1;
+            c++;
+            if (c == mColumns /*end of normal column*/ || r == 0 && c == 2 /*end of 1st column*/) {
+                c = 0;
+                r++;
+            }
+        }
+
+        for (TileRecord record : mRecords) {
+            if (record.tileView.getVisibility() == GONE) continue;
+            record.tileView.setDual(record.row == 0);
+            final int cw = record.row == 0 ? mLargeCellWidth : mCellWidth;
+            final int ch = record.row == 0 ? mLargeCellHeight : mCellHeight;
+            record.tileView.measure(exactly(cw), exactly(ch));
+        }
+        final int actualHeight = rows == 0 ? 0 : getRowTop(rows);
+        mDetail.measure(exactly(width), exactly(actualHeight));
+        setMeasuredDimension(width, actualHeight);
+    }
+
+    private 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 = mCellWidth * mColumns;
+        for (TileRecord record : mRecords) {
+            if (record.tileView.getVisibility() == GONE) continue;
+            final int cols = getColumnCount(record.row);
+            final int cw = record.row == 0 ? mLargeCellWidth : mCellWidth;
+            final int extra = (w - cw * cols) / (cols + 1);
+            final int left = record.col * cw + (record.col + 1) * extra;
+            final int top = getRowTop(record.row);
+            record.tileView.layout(left, top,
+                    left + record.tileView.getMeasuredWidth(),
+                    top + record.tileView.getMeasuredHeight());
+        }
+        mDetail.layout(0, 0, mDetail.getMeasuredWidth(), mDetail.getMeasuredHeight());
+    }
+
+    private int getRowTop(int row) {
+        if (row <= 0) return 0;
+        return mLargeCellHeight + (row - 1) * mCellHeight;
+    }
+
+    private int getColumnCount(int row) {
+        int cols = 0;
+        for (TileRecord record : mRecords) {
+            if (record.tileView.getVisibility() == GONE) continue;
+            if (record.row == row) cols++;
+        }
+        return cols;
+    }
+
+    private class H extends Handler {
+        private static final int SHOW_DETAIL = 1;
+        private static final int SET_TILE_VISIBILITY = 2;
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == SHOW_DETAIL) {
+                handleShowDetail((TileRecord)msg.obj, msg.arg1 != 0);
+            } else if (msg.what == SET_TILE_VISIBILITY) {
+                handleSetTileVisibility((View)msg.obj, msg.arg1 != 0);
+            }
+        }
+    }
+
+    private static final class TileRecord {
+        QSTile<?> tile;
+        QSTileView tileView;
+        int row;
+        int col;
+    }
+
+    private final AnimatorListenerAdapter mTeardownDetailWhenDone = new AnimatorListenerAdapter() {
+        public void onAnimationEnd(Animator animation) {
+            mDetail.removeAllViews();
+            mDetailRecord = null;
+        };
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
new file mode 100644
index 0000000..39c8515
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -0,0 +1,315 @@
+/*
+ * 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.content.Intent;
+import android.graphics.drawable.VectorDrawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.qs.QSTile.State;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.Disposable;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.TetheringController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Base quick-settings tile, extend this to create a new tile.
+ *
+ * State management done on a looper provided by the host.  Tiles should update state in
+ * handleUpdateState.  Callbacks affecting state should use refreshState to trigger another
+ * state update pass on tile looper.
+ */
+public abstract class QSTile<TState extends State> implements Disposable {
+    private final String TAG = "QSTile." + getClass().getSimpleName();
+
+    protected final Host mHost;
+    protected final Context mContext;
+    protected final H mHandler;
+
+    private Callback mCallback;
+    protected final TState mState = newTileState();
+    private final TState mTmpState = newTileState();
+
+    abstract protected TState newTileState();
+    abstract protected void handleClick();
+    abstract protected void handleUpdateState(TState state, Object arg);
+
+    protected QSTile(Host host) {
+        mHost = host;
+        mContext = host.getContext();
+        mHandler = new H(host.getLooper());
+    }
+
+    public Host getHost() {
+        return mHost;
+    }
+
+    public QSTileView createTileView(Context context) {
+        return new QSTileView(context);
+    }
+
+    public View createDetailView(Context context, ViewGroup root) {
+        return null; // optional
+    }
+
+    // safe to call from any thread
+
+    public void setCallback(Callback callback) {
+        mHandler.obtainMessage(H.SET_CALLBACK, callback).sendToTarget();
+    }
+
+    public void click() {
+        mHandler.sendEmptyMessage(H.CLICK);
+    }
+
+    public void secondaryClick() {
+        mHandler.sendEmptyMessage(H.SECONDARY_CLICK);
+    }
+
+    public void showDetail(boolean show) {
+        mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0).sendToTarget();
+    }
+
+    protected final void refreshState() {
+        refreshState(null);
+    }
+
+    protected final void refreshState(Object arg) {
+        mHandler.obtainMessage(H.REFRESH_STATE, arg).sendToTarget();
+    }
+
+    public void userSwitch(int newUserId) {
+        mHandler.obtainMessage(H.USER_SWITCH, newUserId).sendToTarget();
+    }
+
+    public void setShown(boolean shown) {
+        mHandler.obtainMessage(H.SHOWN, shown ? 1 : 0, 0).sendToTarget();
+    }
+
+    // call only on tile worker looper
+
+    private void handleSetCallback(Callback callback) {
+        mCallback = callback;
+        handleRefreshState(null);
+    }
+
+    protected void handleSecondaryClick() {
+        // optional
+    }
+
+    protected void handleShown(boolean shown) {
+        // optional, discouraged
+    }
+
+    protected void handleRefreshState(Object arg) {
+        handleUpdateState(mTmpState, arg);
+        final boolean changed = mTmpState.copyTo(mState);
+        if (changed) {
+            handleStateChanged();
+        }
+    }
+
+    private void handleStateChanged() {
+        if (mCallback != null) {
+            mCallback.onStateChanged(mState);
+        }
+    }
+
+    private void handleShowDetail(boolean show) {
+        if (mCallback != null) {
+            mCallback.onShowDetail(show);
+        }
+    }
+
+    protected void handleUserSwitch(int newUserId) {
+        handleRefreshState(null);
+    }
+
+    protected final class H extends Handler {
+        private static final int SET_CALLBACK = 1;
+        private static final int CLICK = 2;
+        private static final int SECONDARY_CLICK = 3;
+        private static final int REFRESH_STATE = 4;
+        private static final int SHOW_DETAIL = 5;
+        private static final int USER_SWITCH = 6;
+        private static final int SHOWN = 7;
+
+        private H(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            String name = null;
+            try {
+                if (msg.what == SET_CALLBACK) {
+                    name = "handleSetCallback";
+                    handleSetCallback((QSTile.Callback)msg.obj);
+                } else if (msg.what == CLICK) {
+                    name = "handleClick";
+                    handleClick();
+                } else if (msg.what == SECONDARY_CLICK) {
+                    name = "handleSecondaryClick";
+                    handleSecondaryClick();
+                } else if (msg.what == REFRESH_STATE) {
+                    name = "handleRefreshState";
+                    handleRefreshState(msg.obj);
+                } else if (msg.what == SHOW_DETAIL) {
+                    name = "handleShowDetail";
+                    handleShowDetail(msg.arg1 != 0);
+                } else if (msg.what == USER_SWITCH) {
+                    name = "handleUserSwitch";
+                    handleUserSwitch(msg.arg1);
+                } else if (msg.what == SHOWN) {
+                    name = "handleShown";
+                    handleShown(msg.arg1 != 0);
+                }
+            } catch (Throwable t) {
+                final String error = "Error in " + name;
+                Log.w(TAG, error, t);
+                mHost.warn(error, t);
+            }
+        }
+    }
+
+    public interface Callback {
+        void onStateChanged(State state);
+        void onShowDetail(boolean show);
+    }
+
+    public interface Host {
+        void startSettingsActivity(Intent intent);
+        void warn(String message, Throwable t);
+        void collapsePanels();
+        Looper getLooper();
+        Context getContext();
+        VectorDrawable getVectorDrawable(int resId);
+        BluetoothController getBluetoothController();
+        LocationController getLocationController();
+        RotationLockController getRotationLockController();
+        List<QSTile<?>> getTiles();
+        NetworkController getNetworkController();
+        ZenModeController getZenModeController();
+        TetheringController getTetheringController();
+        CastController getCastController();
+    }
+
+    public static class State {
+        public boolean visible;
+        public int iconId;
+        public VectorDrawable icon;
+        public String label;
+        public String contentDescription;
+
+        public boolean copyTo(State other) {
+            if (other == null) throw new IllegalArgumentException();
+            if (!other.getClass().equals(getClass())) throw new IllegalArgumentException();
+            final boolean changed = other.visible != visible
+                    || other.iconId != iconId
+                    || !Objects.equals(other.icon, icon)
+                    || !Objects.equals(other.label, label)
+                    || !Objects.equals(other.contentDescription, contentDescription);
+            other.visible = visible;
+            other.iconId = iconId;
+            other.icon = icon;
+            other.label = label;
+            other.contentDescription = contentDescription;
+            return changed;
+        }
+
+        @Override
+        public String toString() {
+            return toStringBuilder().toString();
+        }
+
+        protected StringBuilder toStringBuilder() {
+            final StringBuilder sb = new StringBuilder(  getClass().getSimpleName()).append('[');
+            sb.append("visible=").append(visible);
+            sb.append(",iconId=").append(iconId);
+            sb.append(",icon=").append(icon);
+            sb.append(",label=").append(label);
+            sb.append(",contentDescription=").append(contentDescription);
+            return sb.append(']');
+        }
+    }
+
+    public static class BooleanState extends State {
+        public boolean value;
+
+        @Override
+        public boolean copyTo(State other) {
+            final BooleanState o = (BooleanState) other;
+            final boolean changed = super.copyTo(other) || o.value != value;
+            o.value = value;
+            return changed;
+        }
+
+        @Override
+        protected StringBuilder toStringBuilder() {
+            final StringBuilder rt = super.toStringBuilder();
+            rt.insert(rt.length() - 1, ",value=" + value);
+            return rt;
+        }
+    }
+
+    public static final class SignalState extends State {
+        public boolean enabled;
+        public boolean connected;
+        public boolean activityIn;
+        public boolean activityOut;
+        public int overlayIconId;
+
+        @Override
+        public boolean copyTo(State other) {
+            final SignalState o = (SignalState) other;
+            final boolean changed = o.enabled != enabled
+                    || o.connected != connected || o.activityIn != activityIn
+                    || o.activityOut != activityOut
+                    || o.overlayIconId != overlayIconId;
+            o.enabled = enabled;
+            o.connected = connected;
+            o.activityIn = activityIn;
+            o.activityOut = activityOut;
+            o.overlayIconId = overlayIconId;
+            return super.copyTo(other) || changed;
+        }
+
+        @Override
+        protected StringBuilder toStringBuilder() {
+            final StringBuilder rt = super.toStringBuilder();
+            rt.insert(rt.length() - 1, ",enabled=" + enabled);
+            rt.insert(rt.length() - 1, ",connected=" + connected);
+            rt.insert(rt.length() - 1, ",activityIn=" + activityIn);
+            rt.insert(rt.length() - 1, ",activityOut=" + activityOut);
+            rt.insert(rt.length() - 1, ",overlayIconId=" + overlayIconId);
+            return rt;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
new file mode 100644
index 0000000..17a95fb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -0,0 +1,190 @@
+/*
+ * 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.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView.ScaleType;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile.State;
+
+/** View that represents a standard quick settings tile. **/
+public class QSTileView extends ViewGroup {
+    private static final Typeface CONDENSED = Typeface.create("sans-serif-condensed",
+            Typeface.NORMAL);
+    private static final int VERTICAL_PADDING_FACTOR = 8;  // internal padding 1/8 the cell height
+
+    protected final Context mContext;
+    private final View mIcon;
+    private final View mDivider;
+    private final TextView mLabel;
+    private final H mHandler = new H();
+
+    private boolean mDual;
+    private OnClickListener mClickPrimary;
+    private OnClickListener mClickSecondary;
+
+    public QSTileView(Context context) {
+        super(context);
+
+        mContext = context;
+        final Resources res = context.getResources();
+        mLabel = new TextView(mContext);
+        mLabel.setId(android.R.id.title);
+        mLabel.setTextColor(res.getColor(R.color.quick_settings_tile_text));
+        mLabel.setGravity(Gravity.CENTER);
+        mLabel.setTypeface(CONDENSED);
+        mLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+                res.getDimensionPixelSize(R.dimen.quick_settings_tile_text_size));
+        addView(mLabel);
+        setClipChildren(false);
+
+        mIcon = createIcon();
+        addView(mIcon);
+
+        mDivider = new View(mContext);
+        mDivider.setBackgroundColor(res.getColor(R.color.quick_settings_tile_divider));
+        final int dh = res.getDimensionPixelSize(R.dimen.quick_settings_tile_divider_height);
+        mDivider.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, dh));
+        addView(mDivider);
+
+        setClickable(true);
+        setBackground(getSelectableBackground());
+    }
+
+    public void setDual(boolean dual) {
+        mDual = dual;
+        if (mDual) {
+            setOnClickListener(mClickPrimary);
+            mLabel.setClickable(true);
+            mLabel.setOnClickListener(mClickSecondary);
+        } else {
+            mLabel.setClickable(false);
+            setOnClickListener(mClickPrimary);
+        }
+        mDivider.setVisibility(dual ? VISIBLE : GONE);
+        postInvalidate();
+    }
+
+    public void init(OnClickListener clickPrimary, OnClickListener clickSecondary) {
+        mClickPrimary = clickPrimary;
+        mClickSecondary = clickSecondary;
+    }
+
+    protected View createIcon() {
+        QSImageView icon = new QSImageView(mContext);
+        icon.setId(android.R.id.icon);
+        icon.setScaleType(ScaleType.CENTER_INSIDE);
+        return icon;
+    }
+
+    private Drawable getSelectableBackground() {
+        final int[] attrs = new int[] { android.R.attr.selectableItemBackground};
+        final TypedArray ta = mContext.obtainStyledAttributes(attrs);
+        final Drawable d = ta.getDrawable(0);
+        ta.recycle();
+        return d;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int w = MeasureSpec.getSize(widthMeasureSpec);
+        final int h = MeasureSpec.getSize(heightMeasureSpec);
+        final int p = h / VERTICAL_PADDING_FACTOR;
+        final int iconSpec = exactly((int)mLabel.getTextSize() * 2);
+        mIcon.measure(iconSpec, iconSpec);
+        mLabel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(h, MeasureSpec.AT_MOST));
+        mLabel.measure(widthMeasureSpec, exactly(mLabel.getMeasuredHeight() + p * 2));
+        if (mDual) {
+            mDivider.measure(widthMeasureSpec, exactly(mDivider.getLayoutParams().height));
+        }
+        setMeasuredDimension(w, h);
+    }
+
+    private 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 = getMeasuredWidth();
+        final int h = getMeasuredHeight();
+        final int p = h / VERTICAL_PADDING_FACTOR;
+        final int contentHeight = p + mIcon.getMeasuredHeight() + mLabel.getMeasuredHeight()
+                + (mDual ? (p + mDivider.getMeasuredHeight()) : 0);
+
+        int top = (h - contentHeight) / 2 + p;
+        final int iconLeft = (w - mIcon.getMeasuredWidth()) / 2;
+        layout(mIcon, iconLeft, top);
+        top = mIcon.getBottom();
+        if (mDual) {
+            top += p;
+            layout(mDivider, 0, top);
+            top = mDivider.getBottom();
+        }
+        layout(mLabel, 0, top);
+    }
+
+    private static void layout(View child, int left, int top) {
+        child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
+    }
+
+    protected void handleStateChanged(QSTile.State state) {
+        if (mIcon instanceof QSImageView) {
+            QSImageView qsiv = (QSImageView) mIcon;
+            if (state.icon != null) {
+                qsiv.setImageDrawable(state.icon);
+            } else if (state.iconId > 0) {
+                qsiv.setImageResource(state.iconId);
+            }
+            if (state.icon != null && state instanceof QSTile.BooleanState) {
+                qsiv.setEnabledVersion(((QSTile.BooleanState)state).value);
+            }
+        }
+        mLabel.setText(state.label);
+        setContentDescription(state.contentDescription);
+    }
+
+    public void onStateChanged(QSTile.State state) {
+        mHandler.obtainMessage(H.STATE_CHANGED, state).sendToTarget();
+    }
+
+    private class H extends Handler {
+        private static final int STATE_CHANGED = 1;
+        public H() {
+            super(Looper.getMainLooper());
+        }
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == STATE_CHANGED) {
+                handleStateChanged((State) msg.obj);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
new file mode 100644
index 0000000..4debaa9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
@@ -0,0 +1,62 @@
+/*
+ * 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.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings.Secure;
+
+import com.android.systemui.statusbar.policy.Disposable;
+
+/** Helper for managing a secure setting. **/
+public abstract class SecureSetting extends ContentObserver implements Disposable {
+    private final Context mContext;
+    private final String mSettingName;
+
+    protected abstract void handleValueChanged(int value);
+
+    public SecureSetting(Context context, Handler handler, String settingName) {
+        super(handler);
+        mContext = context;
+        mSettingName = settingName;
+        rebindForCurrentUser();
+    }
+
+    public void rebindForCurrentUser() {
+        mContext.getContentResolver().registerContentObserver(
+                Secure.getUriFor(mSettingName), false, this);
+    }
+
+    public int getValue() {
+        return Secure.getInt(mContext.getContentResolver(), mSettingName, 0);
+    }
+
+    public void setValue(int value) {
+        Secure.putInt(mContext.getContentResolver(), mSettingName, value);
+    }
+
+    @Override
+    public void dispose() {
+        mContext.getContentResolver().unregisterContentObserver(this);
+    }
+
+    @Override
+    public void onChange(boolean selfChange) {
+        handleValueChanged(getValue());
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
new file mode 100644
index 0000000..7b6c544
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
@@ -0,0 +1,112 @@
+/*
+ * 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.animation.ValueAnimator;
+import android.content.Context;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile.SignalState;
+
+/** View that represents a custom quick settings tile for displaying signal info (wifi/cell). **/
+public final class SignalTileView extends QSTileView {
+    private static final long DEFAULT_DURATION = new ValueAnimator().getDuration();
+    private static final long SHORT_DURATION = DEFAULT_DURATION / 3;
+
+    private FrameLayout mIconFrame;
+    private ImageView mSignal;
+    private ImageView mOverlay;
+    private ImageView mIn;
+    private ImageView mOut;
+
+    public SignalTileView(Context context) {
+        super(context);
+
+        mIn = new ImageView(context);
+        mIn.setImageResource(R.drawable.ic_qs_signal_in);
+        addView(mIn);
+
+        mOut = new ImageView(context);
+        mOut.setImageResource(R.drawable.ic_qs_signal_out);
+        addView(mOut);
+    }
+
+    @Override
+    protected View createIcon() {
+        mIconFrame = new FrameLayout(mContext);
+        mSignal = new ImageView(mContext);
+        mIconFrame.addView(mSignal);
+        mOverlay = new ImageView(mContext);
+        mIconFrame.addView(mOverlay);
+        return mIconFrame;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        int hs = MeasureSpec.makeMeasureSpec(mIconFrame.getMeasuredHeight(), MeasureSpec.EXACTLY);
+        int ws = MeasureSpec.makeMeasureSpec(mIconFrame.getMeasuredHeight(), MeasureSpec.AT_MOST);
+        mIn.measure(ws, hs);
+        mOut.measure(ws, hs);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        layoutIndicator(mIn);
+        layoutIndicator(mOut);
+    }
+
+    private void layoutIndicator(View indicator) {
+        indicator.layout(
+                mIconFrame.getRight(),
+                mIconFrame.getBottom() - indicator.getMeasuredHeight(),
+                mIconFrame.getRight() + indicator.getMeasuredWidth(),
+                mIconFrame.getBottom());
+    }
+
+    @Override
+    protected void handleStateChanged(QSTile.State state) {
+        super.handleStateChanged(state);
+        final SignalState s = (SignalState) state;
+        mSignal.setImageDrawable(null);  // force refresh
+        mSignal.setImageResource(s.iconId);
+        if (s.overlayIconId > 0) {
+            mOverlay.setVisibility(VISIBLE);
+            mOverlay.setImageDrawable(null);  // force refresh
+            mOverlay.setImageResource(s.overlayIconId);
+        } else {
+            mOverlay.setVisibility(GONE);
+        }
+        setVisibility(mIn, s.activityIn);
+        setVisibility(mOut, s.activityOut);
+    }
+
+    private void setVisibility(View view, boolean visible) {
+        final float newAlpha = visible ? 1 : 0;
+        if (view.getAlpha() != newAlpha) {
+            view.animate()
+                .setDuration(visible ? SHORT_DURATION : DEFAULT_DURATION)
+                .alpha(newAlpha)
+                .withLayer()
+                .start();
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
new file mode 100644
index 0000000..5fe8422
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -0,0 +1,100 @@
+/*
+ * 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.tiles;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.provider.Settings.Global;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.GlobalSetting;
+import com.android.systemui.qs.QSTile;
+
+/** Quick settings tile: Airplane mode **/
+public class AirplaneModeTile extends QSTile<QSTile.BooleanState> {
+    private final GlobalSetting mSetting;
+
+    public AirplaneModeTile(Host host) {
+        super(host);
+
+        mSetting = new GlobalSetting(mContext, mHandler, Global.AIRPLANE_MODE_ON) {
+            @Override
+            protected void handleValueChanged(int value) {
+                handleRefreshState(value);
+            }
+        };
+
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        mContext.registerReceiver(mReceiver, filter);
+        refreshState();
+    }
+
+    @Override
+    protected BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void handleClick() {
+        setEnabled(!mState.value);
+    }
+
+    private void setEnabled(boolean enabled) {
+        mSetting.setValue(enabled ? 1 : 0);
+        final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        intent.putExtra("state", enabled);
+        mContext.sendBroadcast(intent);
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        final int value = arg instanceof Integer ? (Integer)arg : mSetting.getValue();
+        final boolean airplaneMode = value != 0;
+        state.value = airplaneMode;
+        state.visible = true;
+        state.label = mContext.getString(R.string.quick_settings_airplane_mode_label);
+        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_airplane);
+        if (airplaneMode) {
+            state.iconId =  R.drawable.ic_qs_airplane_on;
+            state.contentDescription =  mContext.getString(
+                    R.string.accessibility_quick_settings_airplane,
+                    mContext.getString(R.string.accessibility_desc_on));
+        } else {
+            state.iconId = R.drawable.ic_qs_airplane_off;
+            state.contentDescription =  mContext.getString(
+                    R.string.accessibility_quick_settings_airplane,
+                    mContext.getString(R.string.accessibility_desc_off));
+        }
+    }
+
+    public void dispose() {
+        mSetting.dispose();
+        mContext.unregisterReceiver(mReceiver);
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction())) {
+                refreshState();
+            }
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
new file mode 100644
index 0000000..60a6047
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -0,0 +1,93 @@
+/*
+ * 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.tiles;
+
+import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
+import android.content.Intent;
+import android.provider.Settings;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.BluetoothController;
+
+/** Quick settings tile: Bluetooth **/
+public class BluetoothTile extends QSTile<QSTile.BooleanState>  {
+    private static final Intent BLUETOOTH_SETTINGS = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
+
+    private final BluetoothController mController;
+
+    public BluetoothTile(Host host) {
+        super(host);
+        mController = host.getBluetoothController();
+        mController.addStateChangedCallback(mCallback);
+    }
+
+    @Override
+    protected BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void dispose() {
+        mController.removeStateChangedCallback(mCallback);
+    }
+
+    @Override
+    protected void handleClick() {
+        final boolean isEnabled = (Boolean)mState.value;
+        mController.setBluetoothEnabled(!isEnabled);
+    }
+
+    @Override
+    protected void handleSecondaryClick() {
+        mHost.startSettingsActivity(BLUETOOTH_SETTINGS);
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        final boolean supported = mController.isBluetoothSupported();
+        final boolean enabled = mController.isBluetoothEnabled();
+        final boolean connected = mController.isBluetoothConnected();
+        state.visible = supported;
+        state.value = enabled;
+        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_bluetooth);
+        final String stateContentDescription;
+        if (enabled) {
+            if (connected) {
+                state.iconId = R.drawable.ic_qs_bluetooth_on;
+                stateContentDescription = mContext.getString(R.string.accessibility_desc_connected);
+            } else {
+                state.iconId = R.drawable.ic_qs_bluetooth_not_connected;
+                stateContentDescription = mContext.getString(R.string.accessibility_desc_on);
+            }
+            state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
+        } else {
+            state.iconId = R.drawable.ic_qs_bluetooth_off;
+            state.label = mContext.getString(R.string.quick_settings_bluetooth_off_label);
+            stateContentDescription = mContext.getString(R.string.accessibility_desc_off);
+        }
+        state.contentDescription = mContext.getString(
+                R.string.accessibility_quick_settings_bluetooth, stateContentDescription);
+    }
+
+    private final BluetoothStateChangeCallback mCallback = new BluetoothStateChangeCallback() {
+        @Override
+        public void onBluetoothStateChange(boolean on) {
+            refreshState();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
new file mode 100644
index 0000000..1a7b880
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
@@ -0,0 +1,103 @@
+/*
+ * 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.tiles;
+
+import android.app.ActivityManagerNative;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.os.RemoteException;
+import android.provider.Settings.Global;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.GlobalSetting;
+import com.android.systemui.qs.QSTile;
+
+/** Quick settings tile: Bug report **/
+public class BugreportTile extends QSTile<QSTile.State> {
+
+    private final GlobalSetting mSetting;
+
+    public BugreportTile(Host host) {
+        super(host);
+        mSetting = new GlobalSetting(mContext, mHandler, Global.BUGREPORT_IN_POWER_MENU) {
+            @Override
+            protected void handleValueChanged(int value) {
+                handleRefreshState(null);
+            }
+        };
+    }
+
+    @Override
+    protected State newTileState() {
+        return new State();
+    }
+
+    @Override
+    public void dispose() {
+        mSetting.dispose();
+    }
+
+    @Override
+    protected void handleClick() {
+        mHost.collapsePanels();
+        showBugreportDialog();
+    }
+
+    @Override
+    protected void handleUpdateState(State state, Object pushArg) {
+        state.visible = mSetting.getValue() != 0;
+        state.iconId = com.android.internal.R.drawable.stat_sys_adb;
+        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_bugreport);
+        state.label = mContext.getString(com.android.internal.R.string.bugreport_title);
+    }
+
+    private void showBugreportDialog() {
+        final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+        builder.setPositiveButton(com.android.internal.R.string.report, new OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                if (which == DialogInterface.BUTTON_POSITIVE) {
+                    // Add a little delay before executing, to give the
+                    // dialog a chance to go away before it takes a
+                    // screenshot.
+                    mHandler.postDelayed(new Runnable() {
+                        @Override public void run() {
+                            try {
+                                ActivityManagerNative.getDefault().requestBugReport();
+                            } catch (RemoteException e) {
+                            }
+                        }
+                    }, 500);
+                }
+            }
+        });
+        builder.setMessage(com.android.internal.R.string.bugreport_message);
+        builder.setTitle(com.android.internal.R.string.bugreport_title);
+        builder.setCancelable(true);
+        final Dialog dialog = builder.create();
+        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+        try {
+            WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
+        } catch (RemoteException e) {
+        }
+        dialog.show();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
new file mode 100644
index 0000000..e75bb17
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -0,0 +1,123 @@
+/*
+ * 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.tiles;
+
+import android.app.Dialog;
+import android.content.Intent;
+import android.media.MediaRouter;
+import android.provider.Settings;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.internal.app.MediaRouteDialogPresenter;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.CastController;
+
+/** Quick settings tile: Cast **/
+public class CastTile extends QSTile<QSTile.BooleanState> {
+    private static final Intent WIFI_DISPLAY_SETTINGS =
+            new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS);
+
+    private final CastController mController;
+
+    private boolean mShown;
+
+    public CastTile(Host host) {
+        super(host);
+        mController = host.getCastController();
+        if (mController != null) {
+            mController.addCallback(mCallback);
+        }
+    }
+
+    @Override
+    protected BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void dispose() {
+        if (mController == null) return;
+        mController.removeCallback(mCallback);
+    }
+
+    @Override
+    protected void handleUserSwitch(int newUserId) {
+        super.handleUserSwitch(newUserId);
+        if (mController == null) return;
+        mController.setCurrentUserId(newUserId);
+    }
+
+    @Override
+    protected void handleShown(boolean shown) {
+        if (mShown == shown) return;
+        if (mController == null) return;
+        mShown = shown;
+        mController.setDiscovering(mShown);
+    }
+
+    @Override
+    protected void handleClick() {
+        mHost.collapsePanels();
+
+        final Dialog[] dialog = new Dialog[1];
+        dialog[0] = MediaRouteDialogPresenter.createDialog(mContext,
+                MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+                new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                dialog[0].dismiss();
+                mHost.startSettingsActivity(WIFI_DISPLAY_SETTINGS);
+            }
+        });
+        dialog[0].getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
+        dialog[0].show();
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        state.visible = true;
+        state.label = mContext
+                .getString(R.string.quick_settings_remote_display_no_connection_label);
+        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_cast);
+        if (arg instanceof CallbackInfo) {
+            final CallbackInfo cb = (CallbackInfo) arg;
+            if (cb.connectedRouteName != null) {
+                state.value = !cb.connecting;
+            }
+        }
+    }
+
+    private static class CallbackInfo {
+        boolean enabled;
+        boolean connecting;
+        String connectedRouteName;
+    }
+
+    private final CastController.Callback mCallback = new CastController.Callback() {
+        @Override
+        public void onStateChanged(boolean enabled, boolean connecting,
+                String connectedRouteName) {
+            final CallbackInfo info = new CallbackInfo();  // TODO pool
+            info.enabled = enabled;
+            info.connecting = connecting;
+            info.connectedRouteName = connectedRouteName;
+            refreshState(info);
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
new file mode 100644
index 0000000..86a4e79
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -0,0 +1,153 @@
+/*
+ * 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.tiles;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.QSTileView;
+import com.android.systemui.qs.SignalTileView;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+
+/** Quick settings tile: Cellular **/
+public class CellularTile extends QSTile<QSTile.SignalState> {
+    private static final Intent CELLULAR_SETTINGS = new Intent().setComponent(new ComponentName(
+            "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"));
+
+    private final NetworkController mController;
+
+    public CellularTile(Host host) {
+        super(host);
+        mController = host.getNetworkController();
+        mController.addNetworkSignalChangedCallback(mCallback);
+    }
+
+    @Override
+    protected SignalState newTileState() {
+        return new SignalState();
+    }
+
+    @Override
+    public void dispose() {
+        mController.removeNetworkSignalChangedCallback(mCallback);
+    }
+
+    @Override
+    public QSTileView createTileView(Context context) {
+        return new SignalTileView(context);
+    }
+
+    @Override
+    protected void handleClick() {
+        mHost.startSettingsActivity(CELLULAR_SETTINGS);
+    }
+
+    @Override
+    protected void handleUpdateState(SignalState state, Object arg) {
+        state.visible = mController.hasMobileDataFeature();
+        if (!state.visible) return;
+        final CallbackInfo cb = (CallbackInfo) arg;
+        if (cb == null) return;
+
+        final Resources r = mContext.getResources();
+        state.iconId = cb.enabled && (cb.mobileSignalIconId > 0)
+                ? cb.mobileSignalIconId
+                : R.drawable.ic_qs_signal_no_signal;
+        state.overlayIconId = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiEnabled
+                ? cb.dataTypeIconId
+                : 0;
+        state.activityIn = cb.enabled && cb.activityIn;
+        state.activityOut = cb.enabled && cb.activityOut;
+
+        state.label = cb.enabled
+                ? removeTrailingPeriod(cb.enabledDesc)
+                : r.getString(R.string.quick_settings_rssi_emergency_only);
+
+        final String signalContentDesc = cb.enabled && (cb.mobileSignalIconId > 0)
+                ? cb.signalContentDescription
+                : r.getString(R.string.accessibility_no_signal);
+        final String dataContentDesc = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiEnabled
+                ? cb.dataContentDescription
+                : r.getString(R.string.accessibility_no_data);
+        state.contentDescription = r.getString(
+                R.string.accessibility_quick_settings_mobile,
+                signalContentDesc, dataContentDesc,
+                state.label);
+    }
+
+    // Remove the period from the network name
+    public static String removeTrailingPeriod(String string) {
+        if (string == null) return null;
+        final int length = string.length();
+        if (string.endsWith(".")) {
+            return string.substring(0, length - 1);
+        }
+        return string;
+    }
+
+    private static final class CallbackInfo {
+        boolean enabled;
+        boolean wifiEnabled;
+        int mobileSignalIconId;
+        String signalContentDescription;
+        int dataTypeIconId;
+        String dataContentDescription;
+        boolean activityIn;
+        boolean activityOut;
+        String enabledDesc;
+    }
+
+    private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() {
+        private boolean mWifiEnabled;
+
+        @Override
+        public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
+                boolean activityIn, boolean activityOut,
+                String wifiSignalContentDescriptionId, String description) {
+            mWifiEnabled = enabled;
+        }
+
+        @Override
+        public void onMobileDataSignalChanged(boolean enabled,
+                int mobileSignalIconId,
+                String mobileSignalContentDescriptionId, int dataTypeIconId,
+                boolean activityIn, boolean activityOut,
+                String dataTypeContentDescriptionId, String description) {
+            final CallbackInfo info = new CallbackInfo();  // TODO pool?
+            info.enabled = enabled;
+            info.wifiEnabled = mWifiEnabled;
+            info.mobileSignalIconId = mobileSignalIconId;
+            info.signalContentDescription = mobileSignalContentDescriptionId;
+            info.dataTypeIconId = dataTypeIconId;
+            info.dataContentDescription = dataTypeContentDescriptionId;
+            info.activityIn = activityIn;
+            info.activityOut = activityOut;
+            info.enabledDesc = description;
+            refreshState(info);
+        }
+
+        @Override
+        public void onAirplaneModeChanged(boolean enabled) {
+            // noop
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
new file mode 100644
index 0000000..66740af
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -0,0 +1,78 @@
+/*
+ * 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.tiles;
+
+import android.provider.Settings.Secure;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.SecureSetting;
+
+/** Quick settings tile: Invert colors **/
+public class ColorInversionTile extends QSTile<QSTile.BooleanState> {
+
+    private final SecureSetting mSetting;
+
+    private boolean mVisible;
+
+    public ColorInversionTile(Host host) {
+        super(host);
+
+        mSetting = new SecureSetting(mContext, mHandler,
+                Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED) {
+            @Override
+            protected void handleValueChanged(int value) {
+                handleRefreshState(value);
+            }
+        };
+
+        refreshState();
+    }
+
+    @Override
+    protected BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void dispose() {
+        mSetting.dispose();
+    }
+
+    @Override
+    protected void handleUserSwitch(int newUserId) {
+        mSetting.rebindForCurrentUser();
+    }
+
+    @Override
+    protected void handleClick() {
+        mSetting.setValue(mState.value ? 0 : 1);
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue();
+        final boolean enabled = value != 0;
+        if (enabled) {
+            mVisible = true;
+        }
+        state.visible = mVisible;
+        state.value = enabled;
+        state.label = mContext.getString(R.string.quick_settings_inversion_label);
+        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_invert_colors);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
new file mode 100644
index 0000000..1a67afc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -0,0 +1,60 @@
+/*
+ * 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.tiles;
+
+import android.content.Intent;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.TetheringController;
+
+/** Quick settings tile: Hotspot **/
+public class HotspotTile extends QSTile<QSTile.State> {
+    private static final Intent TETHER_SETTINGS = new Intent()
+            .setClassName("com.android.settings", "com.android.settings.TetherSettings");
+
+    // TODO: implement. see com.android.settings.TetherSettings
+
+    private final TetheringController mController;
+
+    public HotspotTile(Host host) {
+        super(host);
+        mController = host.getTetheringController();
+    }
+
+    @Override
+    protected State newTileState() {
+        return new State();
+    }
+
+    @Override
+    public void dispose() {
+
+    }
+
+    @Override
+    protected void handleClick() {
+        mHost.startSettingsActivity(TETHER_SETTINGS);
+    }
+
+    @Override
+    protected void handleUpdateState(State state, Object arg) {
+        state.visible = mController != null;
+        state.label = mContext.getString(R.string.quick_settings_hotspot_label);
+        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_hotspot);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
new file mode 100644
index 0000000..d32f98f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -0,0 +1,82 @@
+/*
+ * 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.tiles;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.LocationController.LocationSettingsChangeCallback;
+
+/** Quick settings tile: Location **/
+public class LocationTile extends QSTile<QSTile.BooleanState> {
+
+    private final LocationController mController;
+
+    public LocationTile(Host host) {
+        super(host);
+        mController = host.getLocationController();
+        mController.addSettingsChangedCallback(mCallback);
+    }
+
+    @Override
+    protected BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    public void dispose() {
+        mController.removeSettingsChangedCallback(mCallback);
+    }
+
+    @Override
+    protected void handleClick() {
+        final boolean wasEnabled = (Boolean) mState.value;
+        final boolean changed = mController.setLocationEnabled(!wasEnabled);
+        if (!wasEnabled && changed) {
+            // If we've successfully switched from location off to on, close the
+            // notifications tray to show the network location provider consent dialog.
+            mHost.collapsePanels();
+        }
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        final boolean locationEnabled =  mController.isLocationEnabled();
+        state.visible = true;
+        state.value = locationEnabled;
+        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_location);
+        if (locationEnabled) {
+            state.iconId = R.drawable.ic_qs_location_on;
+            state.label = mContext.getString(R.string.quick_settings_location_label);
+            state.contentDescription = mContext.getString(
+                    R.string.accessibility_quick_settings_location,
+                    mContext.getString(R.string.accessibility_desc_on));
+        } else {
+            state.iconId = R.drawable.ic_qs_location_off;
+            state.label = mContext.getString(R.string.quick_settings_location_off_label);
+            state.contentDescription = mContext.getString(
+                    R.string.accessibility_quick_settings_location,
+                    mContext.getString(R.string.accessibility_desc_off));
+        }
+    }
+
+    private final LocationSettingsChangeCallback mCallback = new LocationSettingsChangeCallback() {
+        @Override
+        public void onLocationSettingsChanged(boolean enabled) {
+            refreshState();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java
new file mode 100644
index 0000000..36a579c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java
@@ -0,0 +1,105 @@
+/*
+ * 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.tiles;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+
+/** Quick settings tile: Ringer mode **/
+public class RingerModeTile extends QSTile<RingerModeTile.IntState> {
+
+    private final AudioManager mAudioManager;
+
+    public RingerModeTile(Host host) {
+        super(host);
+        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        final IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
+        mContext.registerReceiver(mReceiver, filter);
+    }
+
+    @Override
+    protected IntState newTileState() {
+        return new IntState();
+    }
+
+    @Override
+    public void dispose() {
+        mContext.unregisterReceiver(mReceiver);
+    }
+
+    @Override
+    protected void handleClick() {
+        final int oldValue = (Integer) mState.value;
+        final int newValue =
+                oldValue == AudioManager.RINGER_MODE_NORMAL ? AudioManager.RINGER_MODE_VIBRATE
+              : oldValue == AudioManager.RINGER_MODE_VIBRATE ? AudioManager.RINGER_MODE_SILENT
+              : AudioManager.RINGER_MODE_NORMAL;
+
+        mAudioManager.setRingerMode(newValue);
+    }
+
+    @Override
+    protected void handleUpdateState(IntState state, Object arg) {
+        final int ringerMode = mAudioManager.getRingerMode();
+        state.visible = true;
+        state.value = ringerMode;
+        if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
+            state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_ringer_vibrate);
+            state.label = "Vibrate";
+        } else if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
+            state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_ringer_silent);
+            state.label = "Silent";
+        } else {
+            state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_ringer_audible);
+            state.label = "Audible";
+        }
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(intent.getAction())) {
+                refreshState();
+            }
+        }
+    };
+
+    public static class IntState extends QSTile.State {
+        public int value;
+
+        @Override
+        public boolean copyTo(State other) {
+            final IntState o = (IntState) other;
+            final boolean changed = o.value != value;
+            o.value = value;
+            return super.copyTo(other) || changed;
+        }
+
+        @Override
+        protected StringBuilder toStringBuilder() {
+            final StringBuilder rt = super.toStringBuilder();
+            rt.insert(rt.length() - 1, ",value=" + value);
+            return rt;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
new file mode 100644
index 0000000..1f00824
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -0,0 +1,81 @@
+/*
+ * 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.tiles;
+
+import android.content.res.Configuration;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
+
+/** Quick settings tile: Rotation **/
+public class RotationLockTile extends QSTile<QSTile.BooleanState> {
+
+    private final RotationLockController mController;
+
+    public RotationLockTile(Host host) {
+        super(host);
+        mController = host.getRotationLockController();
+        if (mController == null) return;
+        mController.addRotationLockControllerCallback(mCallback);
+    }
+
+    @Override
+    protected BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    public void dispose() {
+        if (mController == null) return;
+        mController.removeRotationLockControllerCallback(mCallback);
+    }
+
+    @Override
+    protected void handleClick() {
+        if (mController == null) return;
+        mController.setRotationLocked(mState.value);
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        if (mController == null) return;
+        final boolean rotationLocked = mController.isRotationLocked();
+        state.visible = mController.isRotationLockAffordanceVisible();
+        state.value = !rotationLocked;
+        if (rotationLocked) {
+            final int lockOrientation = mController.getRotationLockOrientation();
+            final int label = lockOrientation == Configuration.ORIENTATION_PORTRAIT
+                    ? R.string.quick_settings_rotation_locked_portrait_label
+                    : lockOrientation == Configuration.ORIENTATION_LANDSCAPE
+                    ? R.string.quick_settings_rotation_locked_landscape_label
+                    : R.string.quick_settings_rotation_locked_label;
+            state.iconId = R.drawable.ic_qs_rotation_lock;
+            state.label = mContext.getString(label);
+        } else {
+            state.iconId = R.drawable.ic_qs_rotation;
+            state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label);
+        }
+    }
+
+    private final RotationLockControllerCallback mCallback = new RotationLockControllerCallback() {
+        @Override
+        public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
+            refreshState();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
new file mode 100644
index 0000000..e08a6fa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -0,0 +1,148 @@
+/*
+ * 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.tiles;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.provider.Settings;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.QSTileView;
+import com.android.systemui.qs.SignalTileView;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+
+/** Quick settings tile: Wifi **/
+public class WifiTile extends QSTile<QSTile.SignalState> {
+    private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS);
+
+    private final NetworkController mController;
+
+    public WifiTile(Host host) {
+        super(host);
+        mController = host.getNetworkController();
+        mController.addNetworkSignalChangedCallback(mCallback);
+    }
+
+    @Override
+    protected SignalState newTileState() {
+        return new SignalState();
+    }
+
+    @Override
+    public void dispose() {
+        mController.removeNetworkSignalChangedCallback(mCallback);
+    }
+
+    @Override
+    public QSTileView createTileView(Context context) {
+        return new SignalTileView(context);
+    }
+
+    @Override
+    protected void handleClick() {
+        mController.setWifiEnabled(!mState.enabled);
+    }
+
+    @Override
+    protected void handleSecondaryClick() {
+        mHost.startSettingsActivity(WIFI_SETTINGS);
+    }
+
+    @Override
+    protected void handleUpdateState(SignalState state, Object arg) {
+        if (arg == null) return;
+        state.visible = true;
+        CallbackInfo cb = (CallbackInfo) arg;
+
+        boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.enabledDesc != null);
+        boolean wifiNotConnected = (cb.wifiSignalIconId > 0) && (cb.enabledDesc == null);
+        state.enabled = wifiConnected;
+        state.connected = wifiConnected;
+        state.activityIn = cb.enabled && cb.activityIn;
+        state.activityOut = cb.enabled && cb.activityOut;
+        final String signalContentDescription;
+        final Resources r = mContext.getResources();
+        if (wifiConnected) {
+            state.iconId = cb.wifiSignalIconId;
+            state.label = removeDoubleQuotes(cb.enabledDesc);
+            signalContentDescription = cb.wifiSignalContentDescription;
+        } else if (wifiNotConnected) {
+            state.iconId = R.drawable.ic_qs_wifi_0;
+            state.label = r.getString(R.string.quick_settings_wifi_label);
+            signalContentDescription = r.getString(R.string.accessibility_no_wifi);
+        } else {
+            state.iconId = R.drawable.ic_qs_wifi_no_network;
+            state.label = r.getString(R.string.quick_settings_wifi_off_label);
+            signalContentDescription = r.getString(R.string.accessibility_wifi_off);
+        }
+        state.contentDescription = mContext.getString(
+                R.string.accessibility_quick_settings_wifi,
+                signalContentDescription,
+                state.connected ? state.label : "");
+    }
+
+    private static String removeDoubleQuotes(String string) {
+        if (string == null) return null;
+        final int length = string.length();
+        if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
+            return string.substring(1, length - 1);
+        }
+        return string;
+    }
+
+    private static final class CallbackInfo {
+        boolean enabled;
+        int wifiSignalIconId;
+        String enabledDesc;
+        boolean activityIn;
+        boolean activityOut;
+        String wifiSignalContentDescription;
+    }
+
+    private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() {
+        @Override
+        public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
+                boolean activityIn, boolean activityOut,
+                String wifiSignalContentDescriptionId, String description) {
+            final CallbackInfo info = new CallbackInfo();
+            info.enabled = enabled;
+            info.wifiSignalIconId = wifiSignalIconId;
+            info.enabledDesc = description;
+            info.activityIn = activityIn;
+            info.activityOut = activityOut;
+            info.wifiSignalContentDescription = wifiSignalContentDescriptionId;
+            refreshState(info);
+        }
+
+        @Override
+        public void onMobileDataSignalChanged(boolean enabled,
+                int mobileSignalIconId,
+                String mobileSignalContentDescriptionId, int dataTypeIconId,
+                boolean activityIn, boolean activityOut,
+                String dataTypeContentDescriptionId, String description) {
+            // noop
+        }
+
+        @Override
+        public void onAirplaneModeChanged(boolean enabled) {
+            // noop
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java
new file mode 100644
index 0000000..dceb856
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java
@@ -0,0 +1,279 @@
+/*
+ * 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.tiles;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings;
+import android.service.notification.Condition;
+import android.util.AttributeSet;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.ListView;
+import android.widget.RadioButton;
+import android.widget.RelativeLayout;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSImageView;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import java.util.HashSet;
+
+/** Quick settings control panel: Zen mode **/
+public class ZenModeDetail extends RelativeLayout {
+    private static final String TAG = "ZenModeDetail";
+    private static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+    private static final int[] MINUTES = new int[] { 15, 30, 45, 60, 120, 180, 240 };
+
+    private final H mHandler = new H();
+
+    private int mMinutesIndex = 3;
+    private Context mContext;
+    private ZenModeTile mTile;
+    private QSTile.Host mHost;
+    private ZenModeController mController;
+
+    private Switch mSwitch;
+    private ConditionAdapter mAdapter;
+
+    public ZenModeDetail(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public void init(ZenModeTile tile) {
+        mTile = tile;
+        mHost = mTile.getHost();
+        mContext = getContext();
+        mController = mHost.getZenModeController();
+
+        final QSImageView close = (QSImageView) findViewById(android.R.id.button1);
+        close.setImageDrawable(mHost.getVectorDrawable(R.drawable.ic_qs_close));
+        close.setEnabledVersion(true);
+        close.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mTile.showDetail(false);
+            }
+        });
+        mSwitch = (Switch) findViewById(android.R.id.checkbox);
+        mSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                mController.setZen(isChecked);
+            }
+        });
+        mSwitch.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                final boolean isChecked = mSwitch.isChecked();
+                mController.setZen(isChecked);
+                if (!isChecked) {
+                    mTile.showDetail(false);
+                }
+            }
+        });
+
+        final View moreSettings = findViewById(android.R.id.button2);
+        moreSettings.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mHost.startSettingsActivity(ZEN_SETTINGS);
+                mTile.showDetail(false);
+            }
+        });
+        final ListView conditions = (ListView) findViewById(android.R.id.content);
+        mAdapter = new ConditionAdapter(mContext);
+        conditions.setAdapter(mAdapter);
+        mAdapter.add(updateTimeCondition());
+
+        updateZen(mController.isZen());
+    }
+
+    private Condition updateTimeCondition() {
+        final int minutes = MINUTES[mMinutesIndex];
+        final long millis = System.currentTimeMillis() + minutes * 60 * 1000;
+        final Uri id = new Uri.Builder().scheme(Condition.SCHEME).authority("android")
+                .appendPath("countdown").appendPath(Long.toString(millis)).build();
+        final int num = minutes < 60 ? minutes : minutes / 60;
+        final String units = minutes < 60 ? "minutes" : minutes == 60 ? "hour" : "hours";
+        return new Condition(id, "For " + num + " " + units, "", "", 0, Condition.STATE_TRUE,
+                Condition.FLAG_RELEVANT_NOW);
+    }
+
+    private void editTimeCondition(int delta) {
+        final int i = mMinutesIndex + delta;
+        if (i < 0 || i >= MINUTES.length) return;
+        mMinutesIndex = i;
+        mAdapter.remove(mAdapter.getItem(0));
+        final Condition c = updateTimeCondition();
+        mAdapter.insert(c, 0);
+        select(c);
+    }
+
+    private void select(Condition condition) {
+        mController.select(condition);
+    }
+
+    private void updateZen(boolean zen) {
+        mHandler.obtainMessage(H.UPDATE_ZEN, zen ? 1 : 0, 0).sendToTarget();
+    }
+
+    private void updateConditions(Condition[] conditions) {
+        if (conditions == null) return;
+        mHandler.obtainMessage(H.UPDATE_CONDITIONS, conditions).sendToTarget();
+    }
+
+    private void handleUpdateZen(boolean zen) {
+        mSwitch.setChecked(zen);
+    }
+
+    private void handleUpdateConditions(Condition[] conditions) {
+        for (int i = mAdapter.getCount() - 1; i > 0; i--) {
+            mAdapter.remove(mAdapter.getItem(i));
+        }
+        for (Condition condition : conditions) {
+            mAdapter.add(condition);
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mController.addCallback(mCallback);
+        mController.requestConditions(true);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mController.removeCallback(mCallback);
+        mController.requestConditions(false);
+    }
+
+    private final class H extends Handler {
+        private static final int UPDATE_ZEN = 1;
+        private static final int UPDATE_CONDITIONS = 2;
+
+        public H() {
+            super(Looper.getMainLooper());
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == UPDATE_ZEN) {
+                handleUpdateZen(msg.arg1 == 1);
+            } else if (msg.what == UPDATE_CONDITIONS) {
+                handleUpdateConditions((Condition[])msg.obj);
+            }
+        }
+    }
+
+    private final ZenModeController.Callback mCallback = new ZenModeController.Callback() {
+        @Override
+        public void onZenChanged(boolean zen) {
+            updateZen(zen);
+        }
+        public void onConditionsChanged(Condition[] conditions) {
+            updateConditions(conditions);
+        }
+    };
+
+    private final class ConditionAdapter extends ArrayAdapter<Condition> {
+        private final LayoutInflater mInflater;
+        private final HashSet<RadioButton> mRadioButtons = new HashSet<RadioButton>();
+
+        public ConditionAdapter(Context context) {
+            super(context, 0);
+            mInflater = LayoutInflater.from(new ContextThemeWrapper(context, R.style.QSWhiteTheme));
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            final Condition condition = getItem(position);
+            final boolean enabled = condition.state == Condition.STATE_TRUE;
+
+            final View row = convertView != null ? convertView : mInflater
+                    .inflate(R.layout.qs_zen_mode_detail_condition, parent, false);
+            final RadioButton rb = (RadioButton) row.findViewById(android.R.id.checkbox);
+            mRadioButtons.add(rb);
+            rb.setEnabled(enabled);
+            rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+                @Override
+                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                    if (isChecked) {
+                        for (RadioButton otherButton : mRadioButtons) {
+                            if (otherButton == rb) continue;
+                            otherButton.setChecked(false);
+                        }
+                        select(condition);
+                    }
+                }
+            });
+            final TextView title = (TextView) row.findViewById(android.R.id.title);
+            title.setText(condition.summary);
+            title.setEnabled(enabled);
+            title.setAlpha(enabled ? 1 : .5f);
+            final QSImageView button1 = (QSImageView) row.findViewById(android.R.id.button1);
+            button1.setImageDrawable(mHost.getVectorDrawable(R.drawable.ic_qs_minus));
+            button1.setEnabledVersion(true);
+            button1.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    rb.setChecked(true);
+                    editTimeCondition(-1);
+                }
+            });
+
+            final QSImageView button2 = (QSImageView) row.findViewById(android.R.id.button2);
+            button2.setImageDrawable(mHost.getVectorDrawable(R.drawable.ic_qs_plus));
+            button2.setEnabledVersion(true);
+            button2.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    rb.setChecked(true);
+                    editTimeCondition(1);
+                }
+            });
+            title.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    rb.setChecked(true);
+                }
+            });
+            if (position != 0) {
+                button1.setVisibility(View.GONE);
+                button2.setVisibility(View.GONE);
+            }
+            if (position == 0 && mRadioButtons.size() == 1) {
+                rb.setChecked(true);
+            }
+            return row;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java
new file mode 100644
index 0000000..83918e8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java
@@ -0,0 +1,83 @@
+/*
+ * 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.tiles;
+
+import android.content.Context;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+/** Quick settings tile: Zen mode **/
+public class ZenModeTile extends QSTile<QSTile.BooleanState> {
+    private final ZenModeController mController;
+
+    public ZenModeTile(Host host) {
+        super(host);
+        mController = host.getZenModeController();
+        mController.addCallback(mCallback);
+    }
+
+    @Override
+    public View createDetailView(Context context, ViewGroup root) {
+        final Context themedContext = new ContextThemeWrapper(mContext, R.style.QSAccentTheme);
+        final ZenModeDetail v = (ZenModeDetail) LayoutInflater.from(themedContext)
+                .inflate(R.layout.qs_zen_mode_detail, root, false);
+        v.init(this);
+        return v;
+    }
+
+    @Override
+    protected BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void dispose() {
+        mController.removeCallback(mCallback);
+    }
+
+    @Override
+    protected void handleClick() {
+        final boolean newZen = !mState.value;
+        mController.setZen(newZen);
+        if (newZen) {
+            showDetail(true);
+        }
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        final boolean zen = arg instanceof Boolean ? (Boolean)arg : mController.isZen();
+        state.value = zen;
+        state.visible = true;
+        state.iconId = R.drawable.stat_sys_zen_limited;
+        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_zen);
+        state.label = mContext.getString(R.string.zen_mode_title);
+    }
+
+    private final ZenModeController.Callback mCallback = new ZenModeController.Callback() {
+        @Override
+        public void onZenChanged(boolean zen) {
+            refreshState(zen);
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 89da08f..2bc6f9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -28,19 +28,19 @@
 import android.widget.LinearLayout;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl;
 
 // Intimately tied to the design of res/layout/signal_cluster_view.xml
 public class SignalClusterView
         extends LinearLayout
-        implements NetworkController.SignalCluster {
+        implements NetworkControllerImpl.SignalCluster {
 
     static final boolean DEBUG = false;
     static final String TAG = "SignalClusterView";
     static final PorterDuffColorFilter PROBLEM_FILTER
             = new PorterDuffColorFilter(0xffab653b, PorterDuff.Mode.SRC_ATOP);
 
-    NetworkController mNC;
+    NetworkControllerImpl mNC;
 
     private boolean mWifiVisible = false;
     private int mWifiStrengthId = 0;
@@ -67,7 +67,7 @@
         super(context, attrs, defStyle);
     }
 
-    public void setNetworkController(NetworkController nc) {
+    public void setNetworkController(NetworkControllerImpl nc) {
         if (DEBUG) Log.d(TAG, "NetworkController=" + nc);
         mNC = nc;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index a3cf0f2..869edff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -27,7 +27,7 @@
 import com.android.systemui.DemoMode;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.LocationControllerImpl;
 
 public class DemoStatusIcons extends LinearLayout implements DemoMode {
     private final LinearLayout mStatusIcons;
@@ -74,9 +74,9 @@
             }
             String location = args.getString("location");
             if (location != null) {
-                int iconId = location.equals("show") ? LocationController.LOCATION_STATUS_ICON_ID
+                int iconId = location.equals("show") ? LocationControllerImpl.LOCATION_STATUS_ICON_ID
                         : 0;
-                updateSlot(LocationController.LOCATION_STATUS_ICON_PLACEHOLDER, null, iconId);
+                updateSlot(LocationControllerImpl.LOCATION_STATUS_ICON_PLACEHOLDER, null, iconId);
             }
             String alarm = args.getString("alarm");
             if (alarm != null) {
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 150db63..9054fe3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -45,7 +45,7 @@
 
     PhoneStatusBar mStatusBar;
     private StatusBarHeaderView mHeader;
-    private QuickSettingsContainerView mQsContainer;
+    private View mQsContainer;
     private View mKeyguardStatusView;
     private ObservableScrollView mScrollView;
     private View mStackScrollerContainer;
@@ -106,7 +106,7 @@
         mHeader.setOverlayParent(this);
         mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
         mStackScrollerContainer = findViewById(R.id.notification_container_parent);
-        mQsContainer = (QuickSettingsContainerView) findViewById(R.id.quick_settings_container);
+        mQsContainer = findViewById(R.id.quick_settings_container);
         mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
         mScrollView.setListener(this);
         mNotificationStackScroller = (NotificationStackScrollLayout)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index e7da4f9..922ac05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -92,6 +92,8 @@
 import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
 import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.qs.QSPanel;
+import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.DragDownHelper;
@@ -105,13 +107,15 @@
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
+import com.android.systemui.statusbar.policy.CastControllerImpl;
 import com.android.systemui.statusbar.policy.DateView;
 import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.RotationLockController;
 import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.LocationControllerImpl;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl;
+import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
+import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
 import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
@@ -180,12 +184,14 @@
     PhoneStatusBarPolicy mIconPolicy;
 
     // These are no longer handled by the policy, because we need custom strategies for them
-    BluetoothController mBluetoothController;
+    BluetoothControllerImpl mBluetoothController;
     BatteryController mBatteryController;
-    LocationController mLocationController;
-    NetworkController mNetworkController;
-    RotationLockController mRotationLockController;
+    LocationControllerImpl mLocationController;
+    NetworkControllerImpl mNetworkController;
+    RotationLockControllerImpl mRotationLockController;
     UserInfoController mUserInfoController;
+    ZenModeControllerImpl mZenModeController;
+    CastControllerImpl mCastController;
 
     int mNaturalBarHeight = -1;
     int mIconSize = -1;
@@ -226,9 +232,8 @@
     TextView mNotificationPanelDebugText;
 
     // settings
-    QuickSettings mQS;
     View mFlipSettingsView;
-    QuickSettingsContainerView mSettingsContainer;
+    private QSPanel mQSPanel;
 
     // top bar
     StatusBarHeaderView mHeader;
@@ -660,15 +665,16 @@
         setAreThereNotifications();
 
         // Other icons
-        mLocationController = new LocationController(mContext); // will post a notification
+        mLocationController = new LocationControllerImpl(mContext); // will post a notification
         mBatteryController = new BatteryController(mContext);
-        mNetworkController = new NetworkController(mContext);
-        mBluetoothController = new BluetoothController(mContext);
-        if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)
-                || QuickSettings.DEBUG_GONE_TILES) {
-            mRotationLockController = new RotationLockController(mContext);
+        mNetworkController = new NetworkControllerImpl(mContext);
+        mBluetoothController = new BluetoothControllerImpl(mContext);
+        if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) {
+            mRotationLockController = new RotationLockControllerImpl(mContext);
         }
         mUserInfoController = new UserInfoController(mContext);
+        mZenModeController = new ZenModeControllerImpl(mContext, mHandler);
+        mCastController = new CastControllerImpl(mContext);
         final SignalClusterView signalCluster =
                 (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster);
 
@@ -717,18 +723,17 @@
 //                    updateCarrierLabelVisibility(false);
         }
 
-        // Quick Settings needs a container to survive
-        mSettingsContainer = (QuickSettingsContainerView)
-                mStatusBarWindow.findViewById(R.id.quick_settings_container);
-        mFlipSettingsView = mSettingsContainer;
-        if (mSettingsContainer != null) {
-            mQS = new QuickSettings(mContext, mSettingsContainer);
-            mQS.setService(this);
-            mQS.setBar(mStatusBarView);
-            mQS.setup(mNetworkController, mBluetoothController, mBatteryController,
-                    mLocationController, mRotationLockController);
-        } else {
-            mQS = null; // fly away, be free
+        // Set up the quick settings tile panel
+        mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);
+        if (mQSPanel != null) {
+            final QSTileHost qsh = new QSTileHost(mContext, this,
+                    mBluetoothController, mLocationController, mRotationLockController,
+                    mNetworkController, mZenModeController, null /*tethering*/,
+                    mCastController);
+            for (QSTile<?> tile : qsh.getTiles()) {
+                mQSPanel.addTile(tile);
+            }
+            mHeader.setQSPanel(mQSPanel);
         }
 
         // User info. Trigger first load.
@@ -1471,7 +1476,7 @@
         }
     }
 
-    public Handler getHandler() {
+    private Handler getHandler() {
         return mHandler;
     }
 
@@ -1514,6 +1519,17 @@
         animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
     }
 
+    private final Runnable mAnimateCollapsePanels = new Runnable() {
+        @Override
+        public void run() {
+            animateCollapsePanels();
+        }
+    };
+
+    public void postAnimateCollapsePanels() {
+        mHandler.post(mAnimateCollapsePanels);
+    }
+
     public void animateCollapsePanels(int flags) {
         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
             return;
@@ -1591,7 +1607,7 @@
     final int FLIP_DURATION_IN = 225;
     final int FLIP_DURATION = (FLIP_DURATION_IN + FLIP_DURATION_OUT);
 
-    Animator mScrollViewAnim, mFlipSettingsViewAnim, mClearButtonAnim;
+    Animator mScrollViewAnim, mClearButtonAnim;
 
     @Override
     public void animateExpandNotificationsPanel() {
@@ -1662,7 +1678,6 @@
         mStatusBarView.collapseAllPanels(/*animate=*/ false);
 
         // reset things to their proper state
-        if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
         if (mScrollViewAnim != null) mScrollViewAnim.cancel();
         if (mClearButtonAnim != null) mClearButtonAnim.cancel();
 
@@ -1984,7 +1999,6 @@
         }
 
         setNavigationIconHints(flags);
-        if (mQS != null) mQS.setImeWindowStatus(vis > 0);
     }
 
     @Override
@@ -2383,11 +2397,8 @@
      * meantime, just update the things that we know change.
      */
     void updateResources() {
-        final Context context = mContext;
-        final Resources res = context.getResources();
-
-        // Update the QuickSettings container
-        if (mQS != null) mQS.updateResources();
+        // Update the quick setting tiles
+        if (mQSPanel != null) mQSPanel.updateResources();
 
         loadDimens();
     }
@@ -2546,10 +2557,29 @@
                 || (mDisabled & StatusBarManager.DISABLE_SEARCH) != 0;
     }
 
-    public void startSettingsActivity(String action) {
-        if (mQS != null) {
-            mQS.startSettingsActivity(action);
+    public void postStartSettingsActivity(final Intent intent) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                handleStartSettingsActivity(intent, true /*onlyProvisioned*/);
+            }
+        });
+    }
+
+    private void handleStartSettingsActivity(Intent intent, boolean onlyProvisioned) {
+        if (onlyProvisioned && !isDeviceProvisioned()) return;
+        try {
+            // Dismiss the lock screen when Settings starts.
+            ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+        } catch (RemoteException e) {
         }
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+        animateCollapsePanels();
+    }
+
+    public void startSettingsActivity(String action) {
+        postStartSettingsActivity(new Intent(action));
     }
 
     private static class FastColorDrawable extends Drawable {
@@ -2711,7 +2741,6 @@
             mKeyguardStatusView.setVisibility(View.GONE);
             mKeyguardIndicationTextView.setVisibility(View.GONE);
         }
-        mSettingsContainer.setKeyguardShowing(mState == StatusBarState.KEYGUARD);
         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
             mKeyguardBottomArea.setVisibility(View.VISIBLE);
             mHeader.setKeyguardShowing(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
new file mode 100644
index 0000000..1fe3be5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -0,0 +1,178 @@
+/*
+ * 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.statusbar.phone;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.VectorDrawable;
+import android.os.HandlerThread;
+import android.os.Looper;
+
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.tiles.AirplaneModeTile;
+import com.android.systemui.qs.tiles.BluetoothTile;
+import com.android.systemui.qs.tiles.BugreportTile;
+import com.android.systemui.qs.tiles.CastTile;
+import com.android.systemui.qs.tiles.CellularTile;
+import com.android.systemui.qs.tiles.ColorInversionTile;
+import com.android.systemui.qs.tiles.LocationTile;
+import com.android.systemui.qs.tiles.RingerModeTile;
+import com.android.systemui.qs.tiles.RotationLockTile;
+import com.android.systemui.qs.tiles.HotspotTile;
+import com.android.systemui.qs.tiles.WifiTile;
+import com.android.systemui.qs.tiles.ZenModeTile;
+import com.android.systemui.settings.CurrentUserTracker;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.TetheringController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Platform implementation of the quick settings tile host **/
+public class QSTileHost implements QSTile.Host {
+
+    private final Context mContext;
+    private final PhoneStatusBar mStatusBar;
+    private final BluetoothController mBluetooth;
+    private final LocationController mLocation;
+    private final RotationLockController mRotation;
+    private final NetworkController mNetwork;
+    private final ZenModeController mZen;
+    private final TetheringController mTethering;
+    private final CastController mCast;
+    private final Looper mLooper;
+    private final CurrentUserTracker mUserTracker;
+    private final ArrayList<QSTile<?>> mTiles = new ArrayList<QSTile<?>>();
+
+    public QSTileHost(Context context, PhoneStatusBar statusBar,
+            BluetoothController bluetooth, LocationController location,
+            RotationLockController rotation, NetworkController network,
+            ZenModeController zen, TetheringController tethering,
+            CastController cast) {
+        mContext = context;
+        mStatusBar = statusBar;
+        mBluetooth = bluetooth;
+        mLocation = location;
+        mRotation = rotation;
+        mNetwork = network;
+        mZen = zen;
+        mTethering = tethering;
+        mCast = cast;
+
+        final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName());
+        ht.start();
+        mLooper = ht.getLooper();
+
+        mTiles.add(new WifiTile(this));
+        mTiles.add(new BluetoothTile(this));
+        mTiles.add(new ColorInversionTile(this));
+        mTiles.add(new CellularTile(this));
+        mTiles.add(new AirplaneModeTile(this));
+        mTiles.add(new ZenModeTile(this));
+        mTiles.add(new RingerModeTile(this));
+        mTiles.add(new RotationLockTile(this));
+        mTiles.add(new LocationTile(this));
+        mTiles.add(new CastTile(this));
+        mTiles.add(new HotspotTile(this));
+        mTiles.add(new BugreportTile(this));
+
+        mUserTracker = new CurrentUserTracker(mContext) {
+            @Override
+            public void onUserSwitched(int newUserId) {
+                for (QSTile<?> tile : mTiles) {
+                    tile.userSwitch(newUserId);
+                }
+            }
+        };
+        mUserTracker.startTracking();
+    }
+
+    @Override
+    public List<QSTile<?>> getTiles() {
+        return mTiles;
+    }
+
+    @Override
+    public void startSettingsActivity(final Intent intent) {
+        mStatusBar.postStartSettingsActivity(intent);
+    }
+
+    @Override
+    public void warn(String message, Throwable t) {
+        // already logged
+    }
+
+    @Override
+    public void collapsePanels() {
+        mStatusBar.postAnimateCollapsePanels();
+    }
+
+    @Override
+    public Looper getLooper() {
+        return mLooper;
+    }
+
+    @Override
+    public Context getContext() {
+        return mContext;
+    }
+
+    @Override
+    public VectorDrawable getVectorDrawable(int resId) {
+        return (VectorDrawable) mContext.getDrawable(resId);
+    }
+
+    @Override
+    public BluetoothController getBluetoothController() {
+        return mBluetooth;
+    }
+
+    @Override
+    public LocationController getLocationController() {
+        return mLocation;
+    }
+
+    @Override
+    public RotationLockController getRotationLockController() {
+        return mRotation;
+    }
+
+    @Override
+    public NetworkController getNetworkController() {
+        return mNetwork;
+    }
+
+    @Override
+    public ZenModeController getZenModeController() {
+        return mZen;
+    }
+
+    @Override
+    public TetheringController getTetheringController() {
+        return mTethering;
+    }
+
+    @Override
+    public CastController getCastController() {
+        return mCast;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
deleted file mode 100644
index 8ce7279..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ /dev/null
@@ -1,1119 +0,0 @@
-/*
- * Copyright (C) 2012 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.statusbar.phone;
-
-import android.animation.ValueAnimator;
-import android.app.ActivityManagerNative;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.PendingIntent;
-import android.app.admin.DevicePolicyManager;
-import android.bluetooth.BluetoothAdapter;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.UserInfo;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.hardware.display.DisplayManager;
-import android.media.MediaRouter;
-import android.net.wifi.WifiManager;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.AlarmClock;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.Profile;
-import android.provider.Settings;
-import android.security.KeyChain;
-import android.text.TextUtils.TruncateAt;
-import android.util.Log;
-import android.util.Pair;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-import android.view.WindowManager.LayoutParams;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.internal.app.MediaRouteDialogPresenter;
-import com.android.systemui.R;
-import com.android.systemui.settings.UserSwitcherHostView;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.ActivityState;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.BluetoothState;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.RSSIState;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.State;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.UserState;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.WifiState;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.RotationLockController;
-
-import java.util.ArrayList;
-
-/**
- *
- */
-class QuickSettings {
-    static final boolean DEBUG_GONE_TILES = false;
-    private static final String TAG = "QuickSettings";
-    public static final boolean SHOW_IME_TILE = false;
-    public static final boolean SHOW_ACCESSIBILITY_TILES = true;
-
-    public static final boolean LONG_PRESS_TOGGLES = true;
-
-    private Context mContext;
-    private PanelBar mBar;
-    private QuickSettingsModel mModel;
-    private ViewGroup mContainerView;
-
-    private DevicePolicyManager mDevicePolicyManager;
-    private PhoneStatusBar mStatusBarService;
-    private BluetoothState mBluetoothState;
-    private BluetoothAdapter mBluetoothAdapter;
-    private WifiManager mWifiManager;
-
-    private BluetoothController mBluetoothController;
-    private RotationLockController mRotationLockController;
-    private LocationController mLocationController;
-
-    private AsyncTask<Void, Void, Pair<String, Drawable>> mUserInfoTask;
-    private AsyncTask<Void, Void, Pair<Boolean, Boolean>> mQueryCertTask;
-
-    boolean mTilesSetUp = false;
-    boolean mUseDefaultAvatar = false;
-
-    private Handler mHandler;
-
-    // The set of QuickSettingsTiles that have dynamic spans (and need to be updated on
-    // configuration change)
-    private final ArrayList<QuickSettingsTileView> mDynamicSpannedTiles =
-            new ArrayList<QuickSettingsTileView>();
-
-    public QuickSettings(Context context, QuickSettingsContainerView container) {
-        mDevicePolicyManager
-            = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        mContext = context;
-        mContainerView = container;
-        mModel = new QuickSettingsModel(context);
-        mBluetoothState = new QuickSettingsModel.BluetoothState();
-        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
-        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
-
-        mHandler = new Handler();
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
-        filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
-        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
-        filter.addAction(Intent.ACTION_USER_SWITCHED);
-        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
-        filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
-        mContext.registerReceiver(mReceiver, filter);
-
-        IntentFilter profileFilter = new IntentFilter();
-        profileFilter.addAction(ContactsContract.Intents.ACTION_PROFILE_CHANGED);
-        profileFilter.addAction(Intent.ACTION_USER_INFO_CHANGED);
-        mContext.registerReceiverAsUser(mProfileReceiver, UserHandle.ALL, profileFilter,
-                null, null);
-    }
-
-    void setBar(PanelBar bar) {
-        mBar = bar;
-    }
-
-    public void setService(PhoneStatusBar phoneStatusBar) {
-        mStatusBarService = phoneStatusBar;
-    }
-
-    public PhoneStatusBar getService() {
-        return mStatusBarService;
-    }
-
-    public void setImeWindowStatus(boolean visible) {
-        mModel.onImeWindowStatusChanged(visible);
-    }
-
-    void setup(NetworkController networkController, BluetoothController bluetoothController,
-            BatteryController batteryController, LocationController locationController,
-            RotationLockController rotationLockController) {
-        mBluetoothController = bluetoothController;
-        mRotationLockController = rotationLockController;
-        mLocationController = locationController;
-
-        setupQuickSettings();
-        updateResources();
-        applyLocationEnabledStatus();
-
-        networkController.addNetworkSignalChangedCallback(mModel);
-        bluetoothController.addStateChangedCallback(mModel);
-        batteryController.addStateChangedCallback(mModel);
-        locationController.addSettingsChangedCallback(mModel);
-        if (rotationLockController != null) {
-            rotationLockController.addRotationLockControllerCallback(mModel);
-        }
-    }
-
-    private void queryForSslCaCerts() {
-        mQueryCertTask = new AsyncTask<Void, Void, Pair<Boolean, Boolean>>() {
-            @Override
-            protected Pair<Boolean, Boolean> doInBackground(Void... params) {
-                boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
-                boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null;
-
-                return Pair.create(hasCert, isManaged);
-            }
-            @Override
-            protected void onPostExecute(Pair<Boolean, Boolean> result) {
-                super.onPostExecute(result);
-                boolean hasCert = result.first;
-                boolean isManaged = result.second;
-                mModel.setSslCaCertWarningTileInfo(hasCert, isManaged);
-            }
-        };
-        mQueryCertTask.execute();
-    }
-
-    private void queryForUserInformation() {
-        Context currentUserContext = null;
-        UserInfo userInfo = null;
-        try {
-            userInfo = ActivityManagerNative.getDefault().getCurrentUser();
-            currentUserContext = mContext.createPackageContextAsUser("android", 0,
-                    new UserHandle(userInfo.id));
-        } catch (NameNotFoundException e) {
-            Log.e(TAG, "Couldn't create user context", e);
-            throw new RuntimeException(e);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Couldn't get user info", e);
-        }
-        final int userId = userInfo.id;
-        final String userName = userInfo.name;
-
-        final Context context = currentUserContext;
-        mUserInfoTask = new AsyncTask<Void, Void, Pair<String, Drawable>>() {
-            @Override
-            protected Pair<String, Drawable> doInBackground(Void... params) {
-                final UserManager um = UserManager.get(mContext);
-
-                // Fall back to the UserManager nickname if we can't read the name from the local
-                // profile below.
-                String name = userName;
-                Drawable avatar = null;
-                Bitmap rawAvatar = um.getUserIcon(userId);
-                if (rawAvatar != null) {
-                    avatar = new BitmapDrawable(mContext.getResources(), rawAvatar);
-                } else {
-                    avatar = mContext.getResources().getDrawable(R.drawable.ic_qs_default_user);
-                    mUseDefaultAvatar = true;
-                }
-
-                // If it's a single-user device, get the profile name, since the nickname is not
-                // usually valid
-                if (um.getUsers().size() <= 1) {
-                    // Try and read the display name from the local profile
-                    final Cursor cursor = context.getContentResolver().query(
-                            Profile.CONTENT_URI, new String[] {Phone._ID, Phone.DISPLAY_NAME},
-                            null, null, null);
-                    if (cursor != null) {
-                        try {
-                            if (cursor.moveToFirst()) {
-                                name = cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME));
-                            }
-                        } finally {
-                            cursor.close();
-                        }
-                    }
-                }
-                return new Pair<String, Drawable>(name, avatar);
-            }
-
-            @Override
-            protected void onPostExecute(Pair<String, Drawable> result) {
-                super.onPostExecute(result);
-                mModel.setUserTileInfo(result.first, result.second);
-                mUserInfoTask = null;
-            }
-        };
-        mUserInfoTask.execute();
-    }
-
-    private void setupQuickSettings() {
-        // Setup the tiles that we are going to be showing (including the temporary ones)
-        LayoutInflater inflater = LayoutInflater.from(mContext);
-
-        addUserTiles(mContainerView, inflater);
-        addSystemTiles(mContainerView, inflater);
-        addTemporaryTiles(mContainerView, inflater);
-        addAccessibilityTiles(mContainerView);
-
-        queryForUserInformation();
-        queryForSslCaCerts();
-        mTilesSetUp = true;
-    }
-
-    public void startSettingsActivity(String action) {
-        Intent intent = new Intent(action);
-        startSettingsActivity(intent);
-    }
-
-    private void startSettingsActivity(Intent intent) {
-        startSettingsActivity(intent, true);
-    }
-
-    private void collapsePanels() {
-        getService().animateCollapsePanels();
-    }
-
-    private void startSettingsActivity(Intent intent, boolean onlyProvisioned) {
-        if (onlyProvisioned && !getService().isDeviceProvisioned()) return;
-        try {
-            // Dismiss the lock screen when Settings starts.
-            ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
-        } catch (RemoteException e) {
-        }
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
-        collapsePanels();
-    }
-
-    private void addAccessibilityTiles(ViewGroup parent) {
-        if (!DEBUG_GONE_TILES && !SHOW_ACCESSIBILITY_TILES) return;
-
-        // Color inversion tile
-        final SystemSettingTile inversionTile = new SystemSettingTile(mContext);
-        inversionTile.setUri(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
-                SystemSettingTile.TYPE_SECURE);
-        inversionTile.setFragment("Settings$AccessibilityInversionSettingsActivity");
-        mModel.addInversionTile(inversionTile, inversionTile.getRefreshCallback());
-        parent.addView(inversionTile);
-
-        // Color space adjustment tile
-        final SystemSettingTile colorSpaceTile = new SystemSettingTile(mContext);
-        colorSpaceTile.setUri(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
-                SystemSettingTile.TYPE_SECURE);
-        colorSpaceTile.setFragment("Settings$AccessibilityDaltonizerSettingsActivity");
-        mModel.addColorSpaceTile(colorSpaceTile, colorSpaceTile.getRefreshCallback());
-        parent.addView(colorSpaceTile);
-    }
-
-    private void addUserTiles(final ViewGroup parent, final LayoutInflater inflater) {
-        QuickSettingsTileView userTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        userTile.setContent(R.layout.quick_settings_tile_user, inflater);
-        userTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                final UserManager um = UserManager.get(mContext);
-                if (um.isUserSwitcherEnabled()) {
-                    final ViewGroup switcherParent = getService().getQuickSettingsOverlayParent();
-                    final UserSwitcherHostView switcher = (UserSwitcherHostView) inflater.inflate(
-                            R.layout.user_switcher_host, switcherParent, false);
-                    switcher.setFinishRunnable(new Runnable() {
-                        @Override
-                        public void run() {
-                            switcherParent.removeView(switcher);
-                        }
-                    });
-                    switcher.refreshUsers();
-                    switcherParent.addView(switcher);
-                } else {
-                    collapsePanels();
-                    Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
-                            mContext, v, ContactsContract.Profile.CONTENT_URI,
-                            ContactsContract.QuickContact.MODE_LARGE, null);
-                    mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
-                }
-            }
-        });
-        mModel.addUserTile(userTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView view, State state) {
-                UserState us = (UserState) state;
-                ImageView iv = (ImageView) view.findViewById(R.id.user_imageview);
-                TextView tv = (TextView) view.findViewById(R.id.user_textview);
-                tv.setText(state.label);
-                iv.setImageDrawable(us.avatar);
-                view.setContentDescription(mContext.getString(
-                        R.string.accessibility_quick_settings_user, state.label));
-            }
-        });
-        parent.addView(userTile);
-        mDynamicSpannedTiles.add(userTile);
-
-        // Brightness
-        final QuickSettingsBasicTile brightnessTile
-                = new QuickSettingsBasicTile(mContext);
-        brightnessTile.setImageResource(R.drawable.ic_qs_brightness_auto_off);
-        brightnessTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                collapsePanels();
-                showBrightnessDialog();
-            }
-        });
-        mModel.addBrightnessTile(brightnessTile,
-                new QuickSettingsModel.BasicRefreshCallback(brightnessTile));
-        parent.addView(brightnessTile);
-        mDynamicSpannedTiles.add(brightnessTile);
-
-        // Settings tile
-        final QuickSettingsBasicTile settingsTile = new QuickSettingsBasicTile(mContext);
-        settingsTile.setImageResource(R.drawable.ic_qs_settings);
-        settingsTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                startSettingsActivity(android.provider.Settings.ACTION_SETTINGS);
-            }
-        });
-        mModel.addSettingsTile(settingsTile,
-                new QuickSettingsModel.BasicRefreshCallback(settingsTile));
-        parent.addView(settingsTile);
-        mDynamicSpannedTiles.add(settingsTile);
-    }
-
-    private void addSystemTiles(ViewGroup parent, LayoutInflater inflater) {
-        // Wi-fi
-        final QuickSettingsTileView wifiTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        wifiTile.setContent(R.layout.quick_settings_tile_wifi, inflater);
-        wifiTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                startSettingsActivity(android.provider.Settings.ACTION_WIFI_SETTINGS);
-            }
-        });
-        if (LONG_PRESS_TOGGLES) {
-            wifiTile.setOnLongClickListener(new View.OnLongClickListener() {
-                @Override
-                public boolean onLongClick(View v) {
-                    final boolean enable =
-                            (mWifiManager.getWifiState() != WifiManager.WIFI_STATE_ENABLED);
-                    new AsyncTask<Void, Void, Void>() {
-                        @Override
-                        protected Void doInBackground(Void... args) {
-                            // Disable tethering if enabling Wifi
-                            final int wifiApState = mWifiManager.getWifiApState();
-                            if (enable && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
-                                           (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
-                                mWifiManager.setWifiApEnabled(null, false);
-                            }
-
-                            mWifiManager.setWifiEnabled(enable);
-                            return null;
-                        }
-                    }.execute();
-                    wifiTile.setPressed(false);
-                    return true;
-                }} );
-        }
-        mModel.addWifiTile(wifiTile, new NetworkActivityCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView view, State state) {
-                WifiState wifiState = (WifiState) state;
-                ImageView iv = (ImageView) view.findViewById(R.id.image);
-                iv.setImageResource(wifiState.iconId);
-                setActivity(view, wifiState);
-                TextView tv = (TextView) view.findViewById(R.id.text);
-                tv.setText(wifiState.label);
-                wifiTile.setContentDescription(mContext.getString(
-                        R.string.accessibility_quick_settings_wifi,
-                        wifiState.signalContentDescription,
-                        (wifiState.connected) ? wifiState.label : ""));
-            }
-        });
-        parent.addView(wifiTile);
-
-        if (mModel.deviceHasMobileData()) {
-            // RSSI
-            QuickSettingsTileView rssiTile = (QuickSettingsTileView)
-                    inflater.inflate(R.layout.quick_settings_tile, parent, false);
-            rssiTile.setContent(R.layout.quick_settings_tile_rssi, inflater);
-            rssiTile.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    Intent intent = new Intent();
-                    intent.setComponent(new ComponentName(
-                            "com.android.settings",
-                            "com.android.settings.Settings$DataUsageSummaryActivity"));
-                    startSettingsActivity(intent);
-                }
-            });
-            mModel.addRSSITile(rssiTile, new NetworkActivityCallback() {
-                @Override
-                public void refreshView(QuickSettingsTileView view, State state) {
-                    RSSIState rssiState = (RSSIState) state;
-                    ImageView iv = (ImageView) view.findViewById(R.id.rssi_image);
-                    ImageView iov = (ImageView) view.findViewById(R.id.rssi_overlay_image);
-                    TextView tv = (TextView) view.findViewById(R.id.rssi_textview);
-                    // Force refresh
-                    iv.setImageDrawable(null);
-                    iv.setImageResource(rssiState.signalIconId);
-
-                    if (rssiState.dataTypeIconId > 0) {
-                        iov.setImageResource(rssiState.dataTypeIconId);
-                    } else {
-                        iov.setImageDrawable(null);
-                    }
-                    setActivity(view, rssiState);
-
-                    tv.setText(state.label);
-                    view.setContentDescription(mContext.getResources().getString(
-                            R.string.accessibility_quick_settings_mobile,
-                            rssiState.signalContentDescription, rssiState.dataContentDescription,
-                            state.label));
-                }
-            });
-            parent.addView(rssiTile);
-        }
-
-        // Rotation Lock
-        if (mRotationLockController != null) {
-            final QuickSettingsBasicTile rotationLockTile
-                    = new QuickSettingsBasicTile(mContext);
-            rotationLockTile.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View view) {
-                    final boolean locked = mRotationLockController.isRotationLocked();
-                    mRotationLockController.setRotationLocked(!locked);
-                }
-            });
-            mModel.addRotationLockTile(rotationLockTile, mRotationLockController,
-                    new QuickSettingsModel.RefreshCallback() {
-                        @Override
-                        public void refreshView(QuickSettingsTileView view, State state) {
-                            QuickSettingsModel.RotationLockState rotationLockState =
-                                    (QuickSettingsModel.RotationLockState) state;
-                            view.setVisibility(rotationLockState.visible
-                                    ? View.VISIBLE : View.GONE);
-                            if (state.iconId != 0) {
-                                // needed to flush any cached IDs
-                                rotationLockTile.setImageDrawable(null);
-                                rotationLockTile.setImageResource(state.iconId);
-                            }
-                            if (state.label != null) {
-                                rotationLockTile.setText(state.label);
-                            }
-                        }
-                    });
-            parent.addView(rotationLockTile);
-        }
-
-        // Battery
-        final QuickSettingsTileView batteryTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        batteryTile.setContent(R.layout.quick_settings_tile_battery, inflater);
-        batteryTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                startSettingsActivity(Intent.ACTION_POWER_USAGE_SUMMARY);
-            }
-        });
-        mModel.addBatteryTile(batteryTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView unused, State state) {
-                QuickSettingsModel.BatteryState batteryState =
-                        (QuickSettingsModel.BatteryState) state;
-                String t;
-                if (batteryState.batteryLevel == 100) {
-                    t = mContext.getString(R.string.quick_settings_battery_charged_label);
-                } else {
-                    t = batteryState.pluggedIn
-                        ? mContext.getString(R.string.quick_settings_battery_charging_label,
-                                batteryState.batteryLevel)
-                        : mContext.getString(R.string.status_bar_settings_battery_meter_format,
-                                batteryState.batteryLevel);
-                }
-                ((TextView)batteryTile.findViewById(R.id.text)).setText(t);
-                batteryTile.setContentDescription(
-                        mContext.getString(R.string.accessibility_quick_settings_battery, t));
-            }
-        });
-        parent.addView(batteryTile);
-
-        // Bluetooth
-        if (mModel.deviceSupportsBluetooth()
-                || DEBUG_GONE_TILES) {
-            final QuickSettingsBasicTile bluetoothTile
-                    = new QuickSettingsBasicTile(mContext);
-            bluetoothTile.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    startSettingsActivity(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS);
-                }
-            });
-            if (LONG_PRESS_TOGGLES) {
-                bluetoothTile.setOnLongClickListener(new View.OnLongClickListener() {
-                    @Override
-                    public boolean onLongClick(View v) {
-                        if (mBluetoothAdapter.isEnabled()) {
-                            mBluetoothAdapter.disable();
-                        } else {
-                            mBluetoothAdapter.enable();
-                        }
-                        bluetoothTile.setPressed(false);
-                        return true;
-                    }});
-            }
-            mModel.addBluetoothTile(bluetoothTile, new QuickSettingsModel.RefreshCallback() {
-                @Override
-                public void refreshView(QuickSettingsTileView unused, State state) {
-                    BluetoothState bluetoothState = (BluetoothState) state;
-                    bluetoothTile.setImageResource(state.iconId);
-
-                    /*
-                    Resources r = mContext.getResources();
-                    //TODO: Show connected bluetooth device label
-                    Set<BluetoothDevice> btDevices =
-                            mBluetoothController.getBondedBluetoothDevices();
-                    if (btDevices.size() == 1) {
-                        // Show the name of the bluetooth device you are connected to
-                        label = btDevices.iterator().next().getName();
-                    } else if (btDevices.size() > 1) {
-                        // Show a generic label about the number of bluetooth devices
-                        label = r.getString(R.string.quick_settings_bluetooth_multiple_devices_label,
-                                btDevices.size());
-                    }
-                    */
-                    bluetoothTile.setContentDescription(mContext.getString(
-                            R.string.accessibility_quick_settings_bluetooth,
-                            bluetoothState.stateContentDescription));
-                    bluetoothTile.setText(state.label);
-                }
-            });
-            parent.addView(bluetoothTile);
-        }
-
-        // Location
-        final QuickSettingsBasicTile locationTile
-                = new QuickSettingsBasicTile(mContext);
-        locationTile.setImageResource(R.drawable.ic_qs_location_on);
-        locationTile.setTextResource(R.string.quick_settings_location_label);
-        locationTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                startSettingsActivity(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
-            }
-        });
-        if (LONG_PRESS_TOGGLES) {
-            locationTile.setOnLongClickListener(new View.OnLongClickListener() {
-                @Override
-                public boolean onLongClick(View v) {
-                    boolean newLocationEnabledState = !mLocationController.isLocationEnabled();
-                    if (mLocationController.setLocationEnabled(newLocationEnabledState)
-                            && newLocationEnabledState) {
-                        // If we've successfully switched from location off to on, close the
-                        // notifications tray to show the network location provider consent dialog.
-                        Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-                        mContext.sendBroadcast(closeDialog);
-                    }
-                    return true; // Consume click
-                }} );
-        }
-        mModel.addLocationTile(locationTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView unused, State state) {
-                locationTile.setImageResource(state.iconId);
-                String locationState = mContext.getString(
-                        (state.enabled) ? R.string.accessibility_desc_on
-                                : R.string.accessibility_desc_off);
-                locationTile.setContentDescription(mContext.getString(
-                        R.string.accessibility_quick_settings_location,
-                        locationState));
-                locationTile.setText(state.label);
-            }
-        });
-        parent.addView(locationTile);
-
-        // Airplane Mode
-        final QuickSettingsBasicTile airplaneTile
-                = new QuickSettingsBasicTile(mContext);
-        mModel.addAirplaneModeTile(airplaneTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView unused, State state) {
-                airplaneTile.setImageResource(state.iconId);
-
-                String airplaneState = mContext.getString(
-                        (state.enabled) ? R.string.accessibility_desc_on
-                                : R.string.accessibility_desc_off);
-                airplaneTile.setContentDescription(
-                        mContext.getString(R.string.accessibility_quick_settings_airplane,
-                                airplaneState));
-                airplaneTile.setText(state.label);
-            }
-        });
-        parent.addView(airplaneTile);
-
-        // Zen Mode
-        final QuickSettingsBasicTile zenModeTile = new QuickSettingsBasicTile(mContext);
-        zenModeTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                showZenModeDialog();
-            }
-        });
-        mModel.addZenModeTile(zenModeTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView unused, State state) {
-                zenModeTile.setImageResource(state.iconId);
-                // TODO cut new assets
-                zenModeTile.getImageView().setAlpha(state.enabled ? 1 : .2f);
-                zenModeTile.getImageView().setScaleX(1.5f);
-                zenModeTile.getImageView().setScaleY(1.5f);
-                // for landscape version
-                zenModeTile.getTextView().setMaxLines(2);
-                zenModeTile.getTextView().setEllipsize(TruncateAt.END);
-                // TODO content description
-                zenModeTile.setText(state.label);
-            }
-        });
-        parent.addView(zenModeTile);
-    }
-
-    private void addTemporaryTiles(final ViewGroup parent, final LayoutInflater inflater) {
-        // Alarm tile
-        final QuickSettingsBasicTile alarmTile
-                = new QuickSettingsBasicTile(mContext);
-        alarmTile.setImageResource(R.drawable.ic_qs_alarm_on);
-        alarmTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                startSettingsActivity(AlarmClock.ACTION_SHOW_ALARMS);
-            }
-        });
-        mModel.addAlarmTile(alarmTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView unused, State alarmState) {
-                alarmTile.setText(alarmState.label);
-                alarmTile.setVisibility(alarmState.enabled ? View.VISIBLE : View.GONE);
-                alarmTile.setContentDescription(mContext.getString(
-                        R.string.accessibility_quick_settings_alarm, alarmState.label));
-            }
-        });
-        parent.addView(alarmTile);
-
-        // Remote Display
-        QuickSettingsBasicTile remoteDisplayTile
-                = new QuickSettingsBasicTile(mContext);
-        remoteDisplayTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                collapsePanels();
-
-                final Dialog[] dialog = new Dialog[1];
-                dialog[0] = MediaRouteDialogPresenter.createDialog(mContext,
-                        MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
-                        new View.OnClickListener() {
-                    @Override
-                    public void onClick(View v) {
-                        dialog[0].dismiss();
-                        startSettingsActivity(
-                                android.provider.Settings.ACTION_WIFI_DISPLAY_SETTINGS);
-                    }
-                });
-                dialog[0].getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
-                dialog[0].show();
-            }
-        });
-        mModel.addRemoteDisplayTile(remoteDisplayTile,
-                new QuickSettingsModel.BasicRefreshCallback(remoteDisplayTile)
-                        .setShowWhenEnabled(true));
-        parent.addView(remoteDisplayTile);
-
-        if (SHOW_IME_TILE || DEBUG_GONE_TILES) {
-            // IME
-            final QuickSettingsBasicTile imeTile
-                    = new QuickSettingsBasicTile(mContext);
-            imeTile.setImageResource(R.drawable.ic_qs_ime);
-            imeTile.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    try {
-                        collapsePanels();
-                        Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
-                        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
-                        pendingIntent.send();
-                    } catch (Exception e) {}
-                }
-            });
-            mModel.addImeTile(imeTile,
-                    new QuickSettingsModel.BasicRefreshCallback(imeTile)
-                            .setShowWhenEnabled(true));
-            parent.addView(imeTile);
-        }
-
-        // Bug reports
-        final QuickSettingsBasicTile bugreportTile
-                = new QuickSettingsBasicTile(mContext);
-        bugreportTile.setImageResource(com.android.internal.R.drawable.stat_sys_adb);
-        bugreportTile.setTextResource(com.android.internal.R.string.bugreport_title);
-        bugreportTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                collapsePanels();
-                showBugreportDialog();
-            }
-        });
-        mModel.addBugreportTile(bugreportTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView view, State state) {
-                view.setVisibility(state.enabled ? View.VISIBLE : View.GONE);
-            }
-        });
-        parent.addView(bugreportTile);
-        /*
-        QuickSettingsTileView mediaTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        mediaTile.setContent(R.layout.quick_settings_tile_media, inflater);
-        parent.addView(mediaTile);
-        QuickSettingsTileView imeTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        imeTile.setContent(R.layout.quick_settings_tile_ime, inflater);
-        imeTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                parent.removeViewAt(0);
-            }
-        });
-        parent.addView(imeTile);
-        */
-
-        // SSL CA Cert Warning.
-        final QuickSettingsBasicTile sslCaCertWarningTile =
-                new QuickSettingsBasicTile(mContext, null, R.layout.quick_settings_tile_monitoring);
-        sslCaCertWarningTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                collapsePanels();
-                startSettingsActivity(Settings.ACTION_MONITORING_CERT_INFO);
-            }
-        });
-
-        sslCaCertWarningTile.setImageResource(
-                com.android.internal.R.drawable.indicator_input_error);
-        sslCaCertWarningTile.setTextResource(R.string.ssl_ca_cert_warning);
-
-        mModel.addSslCaCertWarningTile(sslCaCertWarningTile,
-                new QuickSettingsModel.BasicRefreshCallback(sslCaCertWarningTile)
-                        .setShowWhenEnabled(true));
-        parent.addView(sslCaCertWarningTile);
-    }
-
-    void updateResources() {
-        Resources r = mContext.getResources();
-
-        // Update the model
-        mModel.updateResources();
-
-        // Update the User, Time, and Settings tiles spans, and reset everything else
-        int span = r.getInteger(R.integer.quick_settings_user_time_settings_tile_span);
-        for (QuickSettingsTileView v : mDynamicSpannedTiles) {
-            v.setColumnSpan(span);
-        }
-        ((QuickSettingsContainerView)mContainerView).updateResources();
-        mContainerView.requestLayout();
-    }
-
-
-    private void showBrightnessDialog() {
-        Intent intent = new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG);
-        mContext.sendBroadcast(intent);
-    }
-
-    private void showBugreportDialog() {
-        final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
-        builder.setPositiveButton(com.android.internal.R.string.report, new OnClickListener() {
-            @Override
-            public void onClick(DialogInterface dialog, int which) {
-                if (which == DialogInterface.BUTTON_POSITIVE) {
-                    // Add a little delay before executing, to give the
-                    // dialog a chance to go away before it takes a
-                    // screenshot.
-                    mHandler.postDelayed(new Runnable() {
-                        @Override public void run() {
-                            try {
-                                ActivityManagerNative.getDefault()
-                                        .requestBugReport();
-                            } catch (RemoteException e) {
-                            }
-                        }
-                    }, 500);
-                }
-            }
-        });
-        builder.setMessage(com.android.internal.R.string.bugreport_message);
-        builder.setTitle(com.android.internal.R.string.bugreport_title);
-        builder.setCancelable(true);
-        final Dialog dialog = builder.create();
-        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-        try {
-            WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
-        } catch (RemoteException e) {
-        }
-        dialog.show();
-    }
-
-    private void showZenModeDialog() {
-        final Dialog d = new Dialog(mContext);
-        d.requestWindowFeature(Window.FEATURE_NO_TITLE);
-        d.setCancelable(true);
-        d.setCanceledOnTouchOutside(true);
-        final ZenModeView v = new ZenModeView(mContext) {
-            @Override
-            protected void onConfigurationChanged(Configuration newConfig) {
-                super.onConfigurationChanged(newConfig);
-                WindowManager.LayoutParams lp = d.getWindow().getAttributes();
-                lp.width = mContext.getResources()
-                        .getDimensionPixelSize(R.dimen.zen_mode_dialog_width);
-                d.getWindow().setAttributes(lp);
-            }
-        };
-        v.setAutoActivate(true);
-        v.setAdapter(new ZenModeViewAdapter(mContext) {
-            @Override
-            public void configure() {
-                if (mStatusBarService != null) {
-                    mStatusBarService.startSettingsActivity(Settings.ACTION_ZEN_MODE_SETTINGS);
-                }
-                d.dismiss();
-            }
-            @Override
-            public void close() {
-                d.dismiss();
-            }
-        });
-        d.setContentView(v);
-        d.create();
-        d.getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
-        WindowManager.LayoutParams lp = d.getWindow().getAttributes();
-        lp.width = mContext.getResources().getDimensionPixelSize(R.dimen.zen_mode_dialog_width);
-        d.getWindow().setAttributes(lp);
-        d.show();
-    }
-
-    private void applyBluetoothStatus() {
-        mModel.onBluetoothStateChange(mBluetoothState);
-    }
-
-    private void applyLocationEnabledStatus() {
-        mModel.onLocationSettingsChanged(mLocationController.isLocationEnabled());
-    }
-
-    void reloadUserInfo() {
-        if (mUserInfoTask != null) {
-            mUserInfoTask.cancel(false);
-            mUserInfoTask = null;
-        }
-        if (mTilesSetUp) {
-            queryForUserInformation();
-            queryForSslCaCerts();
-        }
-    }
-
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            final String action = intent.getAction();
-            if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
-                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
-                        BluetoothAdapter.ERROR);
-                mBluetoothState.enabled = (state == BluetoothAdapter.STATE_ON);
-                applyBluetoothStatus();
-            } else if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-                int status = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
-                        BluetoothAdapter.STATE_DISCONNECTED);
-                mBluetoothState.connected = (status == BluetoothAdapter.STATE_CONNECTED);
-                applyBluetoothStatus();
-            } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                reloadUserInfo();
-            } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
-                if (mUseDefaultAvatar) {
-                    queryForUserInformation();
-                }
-            } else if (KeyChain.ACTION_STORAGE_CHANGED.equals(action)) {
-                queryForSslCaCerts();
-            }
-        }
-    };
-
-    private final BroadcastReceiver mProfileReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            final String action = intent.getAction();
-            if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) ||
-                    Intent.ACTION_USER_INFO_CHANGED.equals(action)) {
-                try {
-                    final int currentUser = ActivityManagerNative.getDefault().getCurrentUser().id;
-                    final int changedUser =
-                            intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId());
-                    if (changedUser == currentUser) {
-                        reloadUserInfo();
-                    }
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Couldn't get current user id for profile change", e);
-                }
-            }
-
-        }
-    };
-
-    private abstract static class NetworkActivityCallback
-            implements QuickSettingsModel.RefreshCallback {
-        private final long mDefaultDuration = new ValueAnimator().getDuration();
-        private final long mShortDuration = mDefaultDuration / 3;
-
-        public void setActivity(View view, ActivityState state) {
-            setVisibility(view.findViewById(R.id.activity_in), state.activityIn);
-            setVisibility(view.findViewById(R.id.activity_out), state.activityOut);
-        }
-
-        private void setVisibility(View view, boolean visible) {
-            final float newAlpha = visible ? 1 : 0;
-            if (view.getAlpha() != newAlpha) {
-                view.animate()
-                    .setDuration(visible ? mShortDuration : mDefaultDuration)
-                    .alpha(newAlpha)
-                    .start();
-            }
-        }
-    }
-
-    /**
-     * Quick Setting tile that represents a secure setting. This type of tile
-     * can toggle a URI within Settings.Secure on click and launch a Settings
-     * fragment on long-click.
-     */
-    public class SystemSettingTile extends QuickSettingsBasicTile {
-        private static final int TYPE_GLOBAL = 0;
-        private static final int TYPE_SECURE = 1;
-        private static final int TYPE_SYSTEM = 2;
-
-        private final QuickSettingsModel.BasicRefreshCallback mRefreshCallback;
-
-        private String mFragment;
-        private String mName;
-        private int mType;
-
-        public SystemSettingTile(Context context) {
-            super(context);
-
-            mRefreshCallback = new QuickSettingsModel.BasicRefreshCallback(this);
-            mRefreshCallback.setShowWhenEnabled(true);
-        }
-
-        @Override
-        public boolean performLongClick() {
-            if (mFragment != null) {
-                collapsePanels();
-
-                final Intent intent = new Intent();
-                intent.setComponent(new ComponentName(
-                        "com.android.settings", "com.android.settings." + mFragment));
-                startSettingsActivity(intent);
-                return true;
-            }
-            return false;
-        }
-
-        @Override
-        public boolean performClick() {
-            if (mName != null) {
-                collapsePanels();
-
-                final ContentResolver cr = mContext.getContentResolver();
-                switch (mType) {
-                    case TYPE_GLOBAL: {
-                        final boolean enable = Settings.Global.getInt(cr, mName, 0) == 0;
-                        Settings.Global.putInt(cr, mName, enable ? 1 : 0);
-                    } break;
-                    case TYPE_SECURE: {
-                        final boolean enable = Settings.Secure.getIntForUser(
-                                cr, mName, 0, UserHandle.USER_CURRENT) == 0;
-                        Settings.Secure.putIntForUser(
-                                cr, mName, enable ? 1 : 0, UserHandle.USER_CURRENT);
-                    } break;
-                    case TYPE_SYSTEM: {
-                        final boolean enable = Settings.System.getIntForUser(
-                                cr, mName, 0, UserHandle.USER_CURRENT) == 0;
-                        Settings.System.putIntForUser(
-                                cr, mName, enable ? 1 : 0, UserHandle.USER_CURRENT);
-                    } break;
-                }
-                return true;
-            }
-            return false;
-        }
-
-        /**
-         * Specifies the fragment within the com.android.settings package to
-         * launch when this tile is long-clicked.
-         *
-         * @param fragment a fragment name within the com.android.settings
-         *            package
-         */
-        public void setFragment(String fragment) {
-            mFragment = fragment;
-            setLongClickable(fragment != null);
-        }
-
-        /**
-         * Specifies the setting name and type to toggle when this tile is
-         * clicked.
-         *
-         * @param name a setting name
-         * @param type the type of setting, one of:
-         *            <ul>
-         *            <li>{@link #TYPE_GLOBAL}
-         *            <li>{@link #TYPE_SECURE}
-         *            <li>{@link #TYPE_SYSTEM}
-         *            </ul>
-         */
-        public void setUri(String name, int type) {
-            mName = name;
-            mType = type;
-            setClickable(mName != null);
-        }
-
-        /**
-         * @return the refresh callback for this tile
-         */
-        public QuickSettingsModel.BasicRefreshCallback getRefreshCallback() {
-            return mRefreshCallback;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java
deleted file mode 100644
index 099780c..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2013 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.statusbar.phone;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-
-class QuickSettingsBasicTile extends QuickSettingsTileView {
-    private final TextView mTextView;
-    private final ImageView mImageView;
-
-    public QuickSettingsBasicTile(Context context) {
-        this(context, null);
-    }
-
-    public QuickSettingsBasicTile(Context context, AttributeSet attrs) {
-        this(context, attrs, R.layout.quick_settings_tile_basic);
-    }
-
-    public QuickSettingsBasicTile(Context context, AttributeSet attrs, int layoutId) {
-        super(context, attrs);
-
-        setLayoutParams(new FrameLayout.LayoutParams(
-            FrameLayout.LayoutParams.MATCH_PARENT,
-            context.getResources().getDimensionPixelSize(R.dimen.quick_settings_cell_height)
-        ));
-        setBackgroundResource(R.drawable.qs_tile_background);
-        addView(LayoutInflater.from(context).inflate(layoutId, null),
-                new FrameLayout.LayoutParams(
-                        FrameLayout.LayoutParams.MATCH_PARENT,
-                        FrameLayout.LayoutParams.MATCH_PARENT));
-        mTextView = (TextView) findViewById(R.id.text);
-        mImageView = (ImageView) findViewById(R.id.image);
-    }
-
-    @Override
-    void setContent(int layoutId, LayoutInflater inflater) {
-        throw new RuntimeException("why?");
-    }
-
-    public ImageView getImageView() {
-        return mImageView;
-    }
-
-    public TextView getTextView() {
-        return mTextView;
-    }
-
-    public void setImageDrawable(Drawable drawable) {
-        mImageView.setImageDrawable(drawable);
-    }
-
-    public void setImageResource(int resId) {
-        mImageView.setImageResource(resId);
-    }
-
-    public void setText(CharSequence text) {
-        mTextView.setText(text);
-    }
-
-    public void setTextResource(int resId) {
-        mTextView.setText(resId);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java
deleted file mode 100644
index c44cb0c..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Copyright (C) 2012 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.statusbar.phone;
-
-import android.animation.LayoutTransition;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Rect;
-import android.graphics.Typeface;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import com.android.systemui.R;
-
-/**
- *
- */
-class QuickSettingsContainerView extends FrameLayout {
-
-    private static boolean sShowScrim = true;
-
-    private final Context mContext;
-
-    // The number of columns in the QuickSettings grid
-    private int mNumColumns;
-
-    private boolean mKeyguardShowing;
-    private int mMaxRows;
-    private int mMaxRowsOnKeyguard;
-
-    // The gap between tiles in the QuickSettings grid
-    private float mCellGap;
-
-    private ScrimView mScrim;
-
-    public QuickSettingsContainerView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mContext = context;
-        updateResources();
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        if (sShowScrim) {
-            mScrim = new ScrimView(mContext);
-            addView(mScrim);
-        }
-        // TODO: Setup the layout transitions
-        LayoutTransition transitions = getLayoutTransition();
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        if (mScrim != null) {
-            sShowScrim = false;
-            removeView(mScrim);
-        }
-        return super.onTouchEvent(event);
-    }
-
-    void updateResources() {
-        Resources r = getContext().getResources();
-        mCellGap = r.getDimension(R.dimen.quick_settings_cell_gap);
-        mNumColumns = r.getInteger(R.integer.quick_settings_num_columns);
-        mMaxRows = r.getInteger(R.integer.quick_settings_max_rows);
-        mMaxRowsOnKeyguard = r.getInteger(R.integer.quick_settings_max_rows_keyguard);
-        requestLayout();
-    }
-
-    void setKeyguardShowing(boolean showing) {
-        mKeyguardShowing = showing;
-        requestLayout();
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        // Calculate the cell width dynamically
-        int width = MeasureSpec.getSize(widthMeasureSpec);
-        int height = MeasureSpec.getSize(heightMeasureSpec);
-        int availableWidth = (int) (width - getPaddingLeft() - getPaddingRight() -
-                (mNumColumns - 1) * mCellGap);
-        float cellWidth = (float) Math.ceil(((float) availableWidth) / mNumColumns);
-
-        // Update each of the children's widths accordingly to the cell width
-        final int N = getChildCount();
-        int cellHeight = 0;
-        int cursor = 0;
-        int maxRows = mKeyguardShowing ? mMaxRowsOnKeyguard : mMaxRows;
-
-        for (int i = 0; i < N; ++i) {
-            if (getChildAt(i).equals(mScrim)) {
-                continue;
-            }
-            // Update the child's width
-            QuickSettingsTileView v = (QuickSettingsTileView) getChildAt(i);
-            if (v.getVisibility() != View.GONE) {
-                int row = (int) (cursor / mNumColumns);
-                if (row >= maxRows) continue;
-
-                ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
-                int colSpan = v.getColumnSpan();
-                lp.width = (int) ((colSpan * cellWidth) + (colSpan - 1) * mCellGap);
-
-                // Measure the child
-                int newWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
-                int newHeightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
-                v.measure(newWidthSpec, newHeightSpec);
-
-                // Save the cell height
-                if (cellHeight <= 0) {
-                    cellHeight = v.getMeasuredHeight();
-                }
-                cursor += colSpan;
-            }
-        }
-
-        // Set the measured dimensions.  We always fill the tray width, but wrap to the height of
-        // all the tiles.
-        int numRows = (int) Math.ceil((float) cursor / mNumColumns);
-        int newHeight = (int) ((numRows * cellHeight) + ((numRows - 1) * mCellGap)) +
-                getPaddingTop() + getPaddingBottom();
-        setMeasuredDimension(width, newHeight);
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        if (mScrim != null) {
-            mScrim.bringToFront();
-        }
-        final int N = getChildCount();
-        final boolean isLayoutRtl = isLayoutRtl();
-        final int width = getWidth();
-
-        int x = getPaddingStart();
-        int y = getPaddingTop();
-        int cursor = 0;
-        int maxRows = mKeyguardShowing ? mMaxRowsOnKeyguard : mMaxRows;
-
-        for (int i = 0; i < N; ++i) {
-            if (getChildAt(i).equals(mScrim)) {
-                int w = right - left - getPaddingLeft() - getPaddingRight();
-                int h = bottom - top - getPaddingTop() - getPaddingBottom();
-                mScrim.measure(
-                        MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY),
-                        MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY));
-                mScrim.layout(getPaddingLeft(), getPaddingTop(), right, bottom);
-                continue;
-            }
-            QuickSettingsTileView child = (QuickSettingsTileView) getChildAt(i);
-            ViewGroup.LayoutParams lp = child.getLayoutParams();
-            if (child.getVisibility() != GONE) {
-                final int col = cursor % mNumColumns;
-                final int colSpan = child.getColumnSpan();
-
-                final int childWidth = lp.width;
-                final int childHeight = lp.height;
-
-                int row = (int) (cursor / mNumColumns);
-                if (row >= maxRows) continue;
-
-                // Push the item to the next row if it can't fit on this one
-                if ((col + colSpan) > mNumColumns) {
-                    x = getPaddingStart();
-                    y += childHeight + mCellGap;
-                    row++;
-                }
-
-                final int childLeft = (isLayoutRtl) ? width - x - childWidth : x;
-                final int childRight = childLeft + childWidth;
-
-                final int childTop = y;
-                final int childBottom = childTop + childHeight;
-
-                // Layout the container
-                child.layout(childLeft, childTop, childRight, childBottom);
-
-                // Offset the position by the cell gap or reset the position and cursor when we
-                // reach the end of the row
-                cursor += child.getColumnSpan();
-                if (cursor < (((row + 1) * mNumColumns))) {
-                    x += childWidth + mCellGap;
-                } else {
-                    x = getPaddingStart();
-                    y += childHeight + mCellGap;
-                }
-            }
-        }
-    }
-
-    private static final class ScrimView extends View {
-        private static final int SCRIM = 0x4f000000;
-        private static final int COLOR = 0xaf4285f4;
-
-        private final Paint mLinePaint;
-        private final int mStrokeWidth;
-        private final Rect mTmp = new Rect();
-        private final Paint mTextPaint;
-        private final int mTextSize;
-
-        public ScrimView(Context context) {
-            super(context);
-            setFocusable(false);
-            final Resources res = context.getResources();
-            mStrokeWidth = res.getDimensionPixelSize(R.dimen.quick_settings_tmp_scrim_stroke_width);
-            mTextSize = res.getDimensionPixelSize(R.dimen.quick_settings_tmp_scrim_text_size);
-
-            mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-            mLinePaint.setColor(COLOR);
-            mLinePaint.setStrokeWidth(mStrokeWidth);
-            mLinePaint.setStrokeJoin(Paint.Join.ROUND);
-            mLinePaint.setStrokeCap(Paint.Cap.ROUND);
-            mLinePaint.setStyle(Paint.Style.STROKE);
-
-            mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-            mTextPaint.setColor(COLOR);
-            mTextPaint.setTextSize(mTextSize);
-            mTextPaint.setTypeface(Typeface.create("sans-serif-condensed", Typeface.BOLD));
-        }
-
-        @Override
-        protected void onDraw(Canvas canvas) {
-            final int w = getMeasuredWidth();
-            final int h = getMeasuredHeight();
-            final int f = mStrokeWidth * 3 / 4;
-
-            canvas.drawColor(SCRIM);
-            canvas.drawPath(line(f, h / 2, w - f, h / 2), mLinePaint);
-            canvas.drawPath(line(w / 2, f, w / 2, h - f), mLinePaint);
-
-            final int s = mStrokeWidth;
-            mTextPaint.setTextAlign(Paint.Align.RIGHT);
-            canvas.drawText("FUTURE", w / 2 - s, h / 2 - s, mTextPaint);
-            mTextPaint.setTextAlign(Paint.Align.LEFT);
-            canvas.drawText("SITE OF", w / 2 + s, h / 2 - s , mTextPaint);
-            mTextPaint.setTextAlign(Paint.Align.RIGHT);
-            drawUnder(canvas, "QUANTUM", w / 2 - s, h / 2 + s);
-            mTextPaint.setTextAlign(Paint.Align.LEFT);
-            drawUnder(canvas, "SETTINGS", w / 2 + s, h / 2 + s);
-        }
-
-        private void drawUnder(Canvas c, String text, float x, float y) {
-            if (mTmp.isEmpty()) {
-                mTextPaint.getTextBounds(text, 0, text.length(), mTmp);
-            }
-            c.drawText(text, x, y + mTmp.height() * .85f, mTextPaint);
-        }
-
-        private Path line(float x1, float y1, float x2, float y2) {
-            final int a = mStrokeWidth * 2;
-            final Path p = new Path();
-            p.moveTo(x1, y1);
-            p.lineTo(x2, y2);
-            if (y1 == y2) {
-                p.moveTo(x1 + a, y1 + a);
-                p.lineTo(x1, y1);
-                p.lineTo(x1 + a, y1 - a);
-
-                p.moveTo(x2 - a, y2 - a);
-                p.lineTo(x2, y2);
-                p.lineTo(x2 - a, y2 + a);
-            }
-            if (x1 == x2) {
-                p.moveTo(x1 - a, y1 + a);
-                p.lineTo(x1, y1);
-                p.lineTo(x1 + a, y1 + a);
-
-                p.moveTo(x2 - a, y2 - a);
-                p.lineTo(x2, y2);
-                p.lineTo(x2 + a, y2 - a);
-            }
-            return p;
-        }
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
deleted file mode 100644
index 9b90d3d..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ /dev/null
@@ -1,1047 +0,0 @@
-/*
- * Copyright (C) 2012 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.statusbar.phone;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.graphics.drawable.Drawable;
-import android.media.MediaRouter;
-import android.media.MediaRouter.RouteInfo;
-import android.net.ConnectivityManager;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.InputMethodSubtype;
-
-import com.android.systemui.R;
-import com.android.systemui.settings.BrightnessController.BrightnessStateChangeCallback;
-import com.android.systemui.settings.CurrentUserTracker;
-import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
-import com.android.systemui.statusbar.policy.LocationController.LocationSettingsChangeCallback;
-import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
-import com.android.systemui.statusbar.policy.RotationLockController;
-import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
-
-import java.util.List;
-
-class QuickSettingsModel implements BluetoothStateChangeCallback,
-        NetworkSignalChangedCallback,
-        BatteryStateChangeCallback,
-        BrightnessStateChangeCallback,
-        RotationLockControllerCallback,
-        LocationSettingsChangeCallback {
-    // Sett InputMethoManagerService
-    private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
-
-    /** Represents the state of a given attribute. */
-    static class State {
-        int iconId;
-        String label;
-        boolean enabled = false;
-    }
-    static class BatteryState extends State {
-        int batteryLevel;
-        boolean pluggedIn;
-    }
-    static class ActivityState extends State {
-        boolean activityIn;
-        boolean activityOut;
-    }
-    static class RSSIState extends ActivityState {
-        int signalIconId;
-        String signalContentDescription;
-        int dataTypeIconId;
-        String dataContentDescription;
-    }
-    static class WifiState extends ActivityState {
-        String signalContentDescription;
-        boolean connected;
-    }
-    static class UserState extends State {
-        Drawable avatar;
-    }
-    static class BrightnessState extends State {
-        boolean autoBrightness;
-    }
-    static class InversionState extends State {
-        boolean toggled;
-    }
-    static class ColorSpaceState extends State {
-        boolean toggled;
-        int type;
-    }
-    public static class BluetoothState extends State {
-        boolean connected = false;
-        String stateContentDescription;
-    }
-    public static class RotationLockState extends State {
-        boolean visible = false;
-    }
-    public static class ZenModeState extends State {
-        int zenMode = Settings.Global.ZEN_MODE_OFF;
-    }
-
-    /** The callback to update a given tile. */
-    interface RefreshCallback {
-        public void refreshView(QuickSettingsTileView view, State state);
-    }
-
-    public static class BasicRefreshCallback implements RefreshCallback {
-        private final QuickSettingsBasicTile mView;
-        private boolean mShowWhenEnabled;
-
-        public BasicRefreshCallback(QuickSettingsBasicTile v) {
-            mView = v;
-        }
-        public void refreshView(QuickSettingsTileView ignored, State state) {
-            if (mShowWhenEnabled) {
-                mView.setVisibility(state.enabled ? View.VISIBLE : View.GONE);
-            }
-            if (state.iconId != 0) {
-                mView.setImageDrawable(null); // needed to flush any cached IDs
-                mView.setImageResource(state.iconId);
-            }
-            if (state.label != null) {
-                mView.setText(state.label);
-            }
-        }
-        public BasicRefreshCallback setShowWhenEnabled(boolean swe) {
-            mShowWhenEnabled = swe;
-            return this;
-        }
-    }
-
-    /** Broadcast receive to determine if there is an alarm set. */
-    private BroadcastReceiver mAlarmIntentReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
-                onAlarmChanged(intent);
-                onNextAlarmChanged();
-            }
-        }
-    };
-
-    /** ContentObserver to determine the next alarm */
-    private class NextAlarmObserver extends ContentObserver {
-        public NextAlarmObserver(Handler handler) {
-            super(handler);
-        }
-
-        @Override public void onChange(boolean selfChange) {
-            onNextAlarmChanged();
-        }
-
-        public void startObserving() {
-            final ContentResolver cr = mContext.getContentResolver();
-            cr.registerContentObserver(
-                    Settings.System.getUriFor(Settings.System.NEXT_ALARM_FORMATTED), false, this,
-                    UserHandle.USER_ALL);
-        }
-    }
-
-    /** ContentObserver to watch adb */
-    private class BugreportObserver extends ContentObserver {
-        public BugreportObserver(Handler handler) {
-            super(handler);
-        }
-
-        @Override public void onChange(boolean selfChange) {
-            onBugreportChanged();
-        }
-
-        public void startObserving() {
-            final ContentResolver cr = mContext.getContentResolver();
-            cr.registerContentObserver(
-                    Settings.Global.getUriFor(Settings.Global.BUGREPORT_IN_POWER_MENU), false, this);
-        }
-    }
-
-    /** ContentObserver to watch brightness **/
-    private class BrightnessObserver extends ContentObserver {
-        public BrightnessObserver(Handler handler) {
-            super(handler);
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            onBrightnessLevelChanged();
-        }
-
-        public void startObserving() {
-            final ContentResolver cr = mContext.getContentResolver();
-            cr.unregisterContentObserver(this);
-            cr.registerContentObserver(
-                    Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE),
-                    false, this, mUserTracker.getCurrentUserId());
-            cr.registerContentObserver(
-                    Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS),
-                    false, this, mUserTracker.getCurrentUserId());
-        }
-    }
-
-    /** ContentObserver to watch display inversion */
-    private class DisplayInversionObserver extends ContentObserver {
-        public DisplayInversionObserver(Handler handler) {
-            super(handler);
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            onInversionChanged();
-        }
-
-        public void startObserving() {
-            final ContentResolver cr = mContext.getContentResolver();
-            cr.unregisterContentObserver(this);
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED),
-                    false, this, mUserTracker.getCurrentUserId());
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_QUICK_SETTING_ENABLED),
-                    false, this, mUserTracker.getCurrentUserId());
-        }
-    }
-
-    /** ContentObserver to watch display color space adjustment */
-    private class DisplayColorSpaceObserver extends ContentObserver {
-        public DisplayColorSpaceObserver(Handler handler) {
-            super(handler);
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            onColorSpaceChanged();
-        }
-
-        public void startObserving() {
-            final ContentResolver cr = mContext.getContentResolver();
-            cr.unregisterContentObserver(this);
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
-                    false, this, mUserTracker.getCurrentUserId());
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_QUICK_SETTING_ENABLED),
-                    false, this, mUserTracker.getCurrentUserId());
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER),
-                    false, this, mUserTracker.getCurrentUserId());
-        }
-    }
-
-    /** ContentObserver to watch display color space adjustment */
-    private class ZenModeObserver extends ContentObserver {
-        public ZenModeObserver(Handler handler) {
-            super(handler);
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            onZenModeChanged();
-        }
-
-        public void startObserving() {
-            final ContentResolver cr = mContext.getContentResolver();
-            cr.unregisterContentObserver(this);
-            cr.registerContentObserver(
-                    Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false, this);
-        }
-    }
-
-    /** Callback for changes to remote display routes. */
-    private class RemoteDisplayRouteCallback extends MediaRouter.SimpleCallback {
-        @Override
-        public void onRouteAdded(MediaRouter router, RouteInfo route) {
-            updateRemoteDisplays();
-        }
-        @Override
-        public void onRouteChanged(MediaRouter router, RouteInfo route) {
-            updateRemoteDisplays();
-        }
-        @Override
-        public void onRouteRemoved(MediaRouter router, RouteInfo route) {
-            updateRemoteDisplays();
-        }
-        @Override
-        public void onRouteSelected(MediaRouter router, int type, RouteInfo route) {
-            updateRemoteDisplays();
-        }
-        @Override
-        public void onRouteUnselected(MediaRouter router, int type, RouteInfo route) {
-            updateRemoteDisplays();
-        }
-    }
-
-    private final Context mContext;
-    private final Handler mHandler;
-    private final CurrentUserTracker mUserTracker;
-    private final NextAlarmObserver mNextAlarmObserver;
-    private final BugreportObserver mBugreportObserver;
-    private final BrightnessObserver mBrightnessObserver;
-    private final DisplayInversionObserver mInversionObserver;
-    private final DisplayColorSpaceObserver mColorSpaceObserver;
-    private final ZenModeObserver mZenModeObserver;
-
-    private final MediaRouter mMediaRouter;
-    private final RemoteDisplayRouteCallback mRemoteDisplayRouteCallback;
-
-    private final boolean mHasMobileData;
-
-    private QuickSettingsTileView mUserTile;
-    private RefreshCallback mUserCallback;
-    private UserState mUserState = new UserState();
-
-    private QuickSettingsTileView mTimeTile;
-    private RefreshCallback mTimeCallback;
-    private State mTimeState = new State();
-
-    private QuickSettingsTileView mAlarmTile;
-    private RefreshCallback mAlarmCallback;
-    private State mAlarmState = new State();
-
-    private QuickSettingsTileView mAirplaneModeTile;
-    private RefreshCallback mAirplaneModeCallback;
-    private State mAirplaneModeState = new State();
-
-    private QuickSettingsTileView mZenModeTile;
-    private RefreshCallback mZenModeCallback;
-    private ZenModeState mZenModeState = new ZenModeState();
-
-    private QuickSettingsTileView mWifiTile;
-    private RefreshCallback mWifiCallback;
-    private WifiState mWifiState = new WifiState();
-
-    private QuickSettingsTileView mRemoteDisplayTile;
-    private RefreshCallback mRemoteDisplayCallback;
-    private State mRemoteDisplayState = new State();
-
-    private QuickSettingsTileView mRSSITile;
-    private RefreshCallback mRSSICallback;
-    private RSSIState mRSSIState = new RSSIState();
-
-    private QuickSettingsTileView mBluetoothTile;
-    private RefreshCallback mBluetoothCallback;
-    private BluetoothState mBluetoothState = new BluetoothState();
-
-    private QuickSettingsTileView mBatteryTile;
-    private RefreshCallback mBatteryCallback;
-    private BatteryState mBatteryState = new BatteryState();
-
-    private QuickSettingsTileView mLocationTile;
-    private RefreshCallback mLocationCallback;
-    private State mLocationState = new State();
-
-    private QuickSettingsTileView mImeTile;
-    private RefreshCallback mImeCallback = null;
-    private State mImeState = new State();
-
-    private QuickSettingsTileView mRotationLockTile;
-    private RefreshCallback mRotationLockCallback;
-    private RotationLockState mRotationLockState = new RotationLockState();
-
-    private QuickSettingsTileView mBrightnessTile;
-    private RefreshCallback mBrightnessCallback;
-    private BrightnessState mBrightnessState = new BrightnessState();
-
-    private QuickSettingsTileView mInversionTile;
-    private RefreshCallback mInversionCallback;
-    private InversionState mInversionState = new InversionState();
-
-    private QuickSettingsTileView mColorSpaceTile;
-    private RefreshCallback mColorSpaceCallback;
-    private ColorSpaceState mColorSpaceState = new ColorSpaceState();
-
-    private QuickSettingsTileView mBugreportTile;
-    private RefreshCallback mBugreportCallback;
-    private State mBugreportState = new State();
-
-    private QuickSettingsTileView mSettingsTile;
-    private RefreshCallback mSettingsCallback;
-    private State mSettingsState = new State();
-
-    private QuickSettingsTileView mSslCaCertWarningTile;
-    private RefreshCallback mSslCaCertWarningCallback;
-    private State mSslCaCertWarningState = new State();
-
-    private RotationLockController mRotationLockController;
-    private int mRotationLockedLabel;
-
-    public QuickSettingsModel(Context context) {
-        mContext = context;
-        mHandler = new Handler();
-        mUserTracker = new CurrentUserTracker(mContext) {
-            @Override
-            public void onUserSwitched(int newUserId) {
-                mBrightnessObserver.startObserving();
-                mInversionObserver.startObserving();
-                mColorSpaceObserver.startObserving();
-                refreshRotationLockTile();
-                onBrightnessLevelChanged();
-                onInversionChanged();
-                onColorSpaceChanged();
-                onNextAlarmChanged();
-                onBugreportChanged();
-                rebindMediaRouterAsCurrentUser();
-            }
-        };
-        mUserTracker.startTracking();
-
-        mNextAlarmObserver = new NextAlarmObserver(mHandler);
-        mNextAlarmObserver.startObserving();
-        mBugreportObserver = new BugreportObserver(mHandler);
-        mBugreportObserver.startObserving();
-        mBrightnessObserver = new BrightnessObserver(mHandler);
-        mBrightnessObserver.startObserving();
-        mInversionObserver = new DisplayInversionObserver(mHandler);
-        mInversionObserver.startObserving();
-        mColorSpaceObserver = new DisplayColorSpaceObserver(mHandler);
-        mColorSpaceObserver.startObserving();
-        mZenModeObserver = new ZenModeObserver(mHandler);
-        mZenModeObserver.startObserving();
-
-        mMediaRouter = (MediaRouter)context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
-        rebindMediaRouterAsCurrentUser();
-
-        mRemoteDisplayRouteCallback = new RemoteDisplayRouteCallback();
-
-        ConnectivityManager cm = (ConnectivityManager)
-                context.getSystemService(Context.CONNECTIVITY_SERVICE);
-        mHasMobileData = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
-
-        IntentFilter alarmIntentFilter = new IntentFilter();
-        alarmIntentFilter.addAction(Intent.ACTION_ALARM_CHANGED);
-        context.registerReceiver(mAlarmIntentReceiver, alarmIntentFilter);
-    }
-
-    void updateResources() {
-        refreshSettingsTile();
-        refreshBatteryTile();
-        refreshBluetoothTile();
-        refreshBrightnessTile();
-        refreshRotationLockTile();
-        refreshRssiTile();
-        refreshLocationTile();
-    }
-
-    // Settings
-    void addSettingsTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mSettingsTile = view;
-        mSettingsCallback = cb;
-        refreshSettingsTile();
-    }
-    void refreshSettingsTile() {
-        Resources r = mContext.getResources();
-        mSettingsState.label = r.getString(R.string.quick_settings_settings_label);
-        mSettingsCallback.refreshView(mSettingsTile, mSettingsState);
-    }
-
-    // User
-    void addUserTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mUserTile = view;
-        mUserCallback = cb;
-        mUserCallback.refreshView(mUserTile, mUserState);
-    }
-    void setUserTileInfo(String name, Drawable avatar) {
-        mUserState.label = name;
-        mUserState.avatar = avatar;
-        mUserCallback.refreshView(mUserTile, mUserState);
-    }
-
-    // Time
-    void addTimeTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mTimeTile = view;
-        mTimeCallback = cb;
-        mTimeCallback.refreshView(view, mTimeState);
-    }
-
-    // Alarm
-    void addAlarmTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mAlarmTile = view;
-        mAlarmCallback = cb;
-        mAlarmCallback.refreshView(view, mAlarmState);
-    }
-    void onAlarmChanged(Intent intent) {
-        mAlarmState.enabled = intent.getBooleanExtra("alarmSet", false);
-        mAlarmCallback.refreshView(mAlarmTile, mAlarmState);
-    }
-    void onNextAlarmChanged() {
-        final String alarmText = Settings.System.getStringForUser(mContext.getContentResolver(),
-                Settings.System.NEXT_ALARM_FORMATTED,
-                UserHandle.USER_CURRENT);
-        mAlarmState.label = alarmText;
-
-        // When switching users, this is the only clue we're going to get about whether the
-        // alarm is actually set, since we won't get the ACTION_ALARM_CHANGED broadcast
-        mAlarmState.enabled = ! TextUtils.isEmpty(alarmText);
-
-        mAlarmCallback.refreshView(mAlarmTile, mAlarmState);
-    }
-
-    // Airplane Mode
-    void addAirplaneModeTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mAirplaneModeTile = view;
-        mAirplaneModeTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                if (mAirplaneModeState.enabled) {
-                    setAirplaneModeState(false);
-                } else {
-                    setAirplaneModeState(true);
-                }
-            }
-        });
-        mAirplaneModeCallback = cb;
-        int airplaneMode = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_ON, 0);
-        onAirplaneModeChanged(airplaneMode != 0);
-    }
-    private void setAirplaneModeState(boolean enabled) {
-        // TODO: Sets the view to be "awaiting" if not already awaiting
-
-        // Change the system setting
-        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,
-                                enabled ? 1 : 0);
-
-        // Post the intent
-        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        intent.putExtra("state", enabled);
-        mContext.sendBroadcast(intent);
-    }
-    // NetworkSignalChanged callback
-    @Override
-    public void onAirplaneModeChanged(boolean enabled) {
-        // TODO: If view is in awaiting state, disable
-        Resources r = mContext.getResources();
-        mAirplaneModeState.enabled = enabled;
-        mAirplaneModeState.iconId = (enabled ?
-                R.drawable.ic_qs_airplane_on :
-                R.drawable.ic_qs_airplane_off);
-        mAirplaneModeState.label = r.getString(R.string.quick_settings_airplane_mode_label);
-        mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState);
-    }
-
-    // Zen Mode
-    void addZenModeTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mZenModeTile = view;
-        mZenModeCallback = cb;
-        onZenModeChanged();
-    }
-    private void onZenModeChanged() {
-        final int mode = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
-        mZenModeState.enabled = mode != Settings.Global.ZEN_MODE_OFF;
-        mZenModeState.zenMode = mode;
-        mZenModeState.label = mContext.getString(R.string.zen_mode_title);
-        mZenModeState.iconId = R.drawable.stat_sys_zen_limited;
-        mZenModeCallback.refreshView(mZenModeTile, mZenModeState);
-    }
-
-    // Wifi
-    void addWifiTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mWifiTile = view;
-        mWifiCallback = cb;
-        mWifiCallback.refreshView(mWifiTile, mWifiState);
-    }
-    // Remove the double quotes that the SSID may contain
-    public static String removeDoubleQuotes(String string) {
-        if (string == null) return null;
-        final int length = string.length();
-        if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
-            return string.substring(1, length - 1);
-        }
-        return string;
-    }
-    // Remove the period from the network name
-    public static String removeTrailingPeriod(String string) {
-        if (string == null) return null;
-        final int length = string.length();
-        if (string.endsWith(".")) {
-            return string.substring(0, length - 1);
-        }
-        return string;
-    }
-    // NetworkSignalChanged callback
-    @Override
-    public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
-            boolean activityIn, boolean activityOut,
-            String wifiSignalContentDescription, String enabledDesc) {
-        // TODO: If view is in awaiting state, disable
-        Resources r = mContext.getResources();
-
-        boolean wifiConnected = enabled && (wifiSignalIconId > 0) && (enabledDesc != null);
-        boolean wifiNotConnected = (wifiSignalIconId > 0) && (enabledDesc == null);
-        mWifiState.enabled = enabled;
-        mWifiState.connected = wifiConnected;
-        mWifiState.activityIn = enabled && activityIn;
-        mWifiState.activityOut = enabled && activityOut;
-        if (wifiConnected) {
-            mWifiState.iconId = wifiSignalIconId;
-            mWifiState.label = removeDoubleQuotes(enabledDesc);
-            mWifiState.signalContentDescription = wifiSignalContentDescription;
-        } else if (wifiNotConnected) {
-            mWifiState.iconId = R.drawable.ic_qs_wifi_0;
-            mWifiState.label = r.getString(R.string.quick_settings_wifi_label);
-            mWifiState.signalContentDescription = r.getString(R.string.accessibility_no_wifi);
-        } else {
-            mWifiState.iconId = R.drawable.ic_qs_wifi_no_network;
-            mWifiState.label = r.getString(R.string.quick_settings_wifi_off_label);
-            mWifiState.signalContentDescription = r.getString(R.string.accessibility_wifi_off);
-        }
-        mWifiCallback.refreshView(mWifiTile, mWifiState);
-    }
-
-    boolean deviceHasMobileData() {
-        return mHasMobileData;
-    }
-
-    // RSSI
-    void addRSSITile(QuickSettingsTileView view, RefreshCallback cb) {
-        mRSSITile = view;
-        mRSSICallback = cb;
-        mRSSICallback.refreshView(mRSSITile, mRSSIState);
-    }
-    // NetworkSignalChanged callback
-    @Override
-    public void onMobileDataSignalChanged(
-            boolean enabled, int mobileSignalIconId, String signalContentDescription,
-            int dataTypeIconId, boolean activityIn, boolean activityOut,
-            String dataContentDescription,String enabledDesc) {
-        if (deviceHasMobileData()) {
-            // TODO: If view is in awaiting state, disable
-            Resources r = mContext.getResources();
-            mRSSIState.signalIconId = enabled && (mobileSignalIconId > 0)
-                    ? mobileSignalIconId
-                    : R.drawable.ic_qs_signal_no_signal;
-            mRSSIState.signalContentDescription = enabled && (mobileSignalIconId > 0)
-                    ? signalContentDescription
-                    : r.getString(R.string.accessibility_no_signal);
-            mRSSIState.dataTypeIconId = enabled && (dataTypeIconId > 0) && !mWifiState.enabled
-                    ? dataTypeIconId
-                    : 0;
-            mRSSIState.activityIn = enabled && activityIn;
-            mRSSIState.activityOut = enabled && activityOut;
-            mRSSIState.dataContentDescription = enabled && (dataTypeIconId > 0) && !mWifiState.enabled
-                    ? dataContentDescription
-                    : r.getString(R.string.accessibility_no_data);
-            mRSSIState.label = enabled
-                    ? removeTrailingPeriod(enabledDesc)
-                    : r.getString(R.string.quick_settings_rssi_emergency_only);
-            mRSSICallback.refreshView(mRSSITile, mRSSIState);
-        }
-    }
-
-    void refreshRssiTile() {
-        if (mRSSITile != null) {
-            // We reinflate the original view due to potential styling changes that may have
-            // taken place due to a configuration change.
-            mRSSITile.reinflateContent(LayoutInflater.from(mContext));
-        }
-    }
-
-    // Bluetooth
-    void addBluetoothTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mBluetoothTile = view;
-        mBluetoothCallback = cb;
-
-        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        mBluetoothState.enabled = adapter.isEnabled();
-        mBluetoothState.connected =
-                (adapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED);
-        onBluetoothStateChange(mBluetoothState);
-    }
-    boolean deviceSupportsBluetooth() {
-        return (BluetoothAdapter.getDefaultAdapter() != null);
-    }
-    // BluetoothController callback
-    @Override
-    public void onBluetoothStateChange(boolean on) {
-        mBluetoothState.enabled = on;
-        onBluetoothStateChange(mBluetoothState);
-    }
-    public void onBluetoothStateChange(BluetoothState bluetoothStateIn) {
-        // TODO: If view is in awaiting state, disable
-        Resources r = mContext.getResources();
-        mBluetoothState.enabled = bluetoothStateIn.enabled;
-        mBluetoothState.connected = bluetoothStateIn.connected;
-        if (mBluetoothState.enabled) {
-            if (mBluetoothState.connected) {
-                mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_on;
-                mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_connected);
-            } else {
-                mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_not_connected;
-                mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_on);
-            }
-            mBluetoothState.label = r.getString(R.string.quick_settings_bluetooth_label);
-        } else {
-            mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_off;
-            mBluetoothState.label = r.getString(R.string.quick_settings_bluetooth_off_label);
-            mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_off);
-        }
-        mBluetoothCallback.refreshView(mBluetoothTile, mBluetoothState);
-    }
-    void refreshBluetoothTile() {
-        if (mBluetoothTile != null) {
-            onBluetoothStateChange(mBluetoothState.enabled);
-        }
-    }
-
-    // Battery
-    void addBatteryTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mBatteryTile = view;
-        mBatteryCallback = cb;
-        mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
-    }
-    // BatteryController callback
-    @Override
-    public void onBatteryLevelChanged(int level, boolean pluggedIn) {
-        mBatteryState.batteryLevel = level;
-        mBatteryState.pluggedIn = pluggedIn;
-        mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
-    }
-    void refreshBatteryTile() {
-        mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
-    }
-
-    // Location
-    void addLocationTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mLocationTile = view;
-        mLocationCallback = cb;
-        mLocationCallback.refreshView(mLocationTile, mLocationState);
-    }
-
-    void refreshLocationTile() {
-        if (mLocationTile != null) {
-            onLocationSettingsChanged(mLocationState.enabled);
-        }
-    }
-
-    @Override
-    public void onLocationSettingsChanged(boolean locationEnabled) {
-        int textResId = locationEnabled ? R.string.quick_settings_location_label
-                : R.string.quick_settings_location_off_label;
-        String label = mContext.getText(textResId).toString();
-        int locationIconId = locationEnabled
-                ? R.drawable.ic_qs_location_on : R.drawable.ic_qs_location_off;
-        mLocationState.enabled = locationEnabled;
-        mLocationState.label = label;
-        mLocationState.iconId = locationIconId;
-        mLocationCallback.refreshView(mLocationTile, mLocationState);
-    }
-
-    // Bug report
-    void addBugreportTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mBugreportTile = view;
-        mBugreportCallback = cb;
-        onBugreportChanged();
-    }
-    // SettingsObserver callback
-    public void onBugreportChanged() {
-        final ContentResolver cr = mContext.getContentResolver();
-        boolean enabled = false;
-        try {
-            enabled = (Settings.Global.getInt(cr, Settings.Global.BUGREPORT_IN_POWER_MENU) != 0);
-        } catch (SettingNotFoundException e) {
-        }
-
-        mBugreportState.enabled = enabled && mUserTracker.isCurrentUserOwner();
-        mBugreportCallback.refreshView(mBugreportTile, mBugreportState);
-    }
-
-    // Remote Display
-    void addRemoteDisplayTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mRemoteDisplayTile = view;
-        mRemoteDisplayCallback = cb;
-        mRemoteDisplayTile.setOnPrepareListener(new QuickSettingsTileView.OnPrepareListener() {
-            @Override
-            public void onPrepare() {
-                mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
-                        mRemoteDisplayRouteCallback,
-                        MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
-                updateRemoteDisplays();
-            }
-            @Override
-            public void onUnprepare() {
-                mMediaRouter.removeCallback(mRemoteDisplayRouteCallback);
-            }
-        });
-
-        updateRemoteDisplays();
-    }
-
-    private void rebindMediaRouterAsCurrentUser() {
-        mMediaRouter.rebindAsUser(mUserTracker.getCurrentUserId());
-    }
-
-    private void updateRemoteDisplays() {
-        MediaRouter.RouteInfo connectedRoute = mMediaRouter.getSelectedRoute(
-                MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
-        boolean enabled = connectedRoute != null
-                && connectedRoute.matchesTypes(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
-        boolean connecting;
-        if (enabled) {
-            connecting = connectedRoute.isConnecting();
-        } else {
-            connectedRoute = null;
-            connecting = false;
-            enabled = mMediaRouter.isRouteAvailable(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
-                    MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE);
-        }
-
-        mRemoteDisplayState.enabled = enabled;
-        if (connectedRoute != null) {
-            mRemoteDisplayState.label = connectedRoute.getName().toString();
-            mRemoteDisplayState.iconId = connecting ?
-                    R.drawable.ic_qs_cast_connecting : R.drawable.ic_qs_cast_connected;
-        } else {
-            mRemoteDisplayState.label = mContext.getString(
-                    R.string.quick_settings_remote_display_no_connection_label);
-            mRemoteDisplayState.iconId = R.drawable.ic_qs_cast_available;
-        }
-        mRemoteDisplayCallback.refreshView(mRemoteDisplayTile, mRemoteDisplayState);
-    }
-
-    // IME
-    void addImeTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mImeTile = view;
-        mImeCallback = cb;
-        mImeCallback.refreshView(mImeTile, mImeState);
-    }
-    /* This implementation is taken from
-       InputMethodManagerService.needsToShowImeSwitchOngoingNotification(). */
-    private boolean needsToShowImeSwitchOngoingNotification(InputMethodManager imm) {
-        List<InputMethodInfo> imis = imm.getEnabledInputMethodList();
-        final int N = imis.size();
-        if (N > 2) return true;
-        if (N < 1) return false;
-        int nonAuxCount = 0;
-        int auxCount = 0;
-        InputMethodSubtype nonAuxSubtype = null;
-        InputMethodSubtype auxSubtype = null;
-        for(int i = 0; i < N; ++i) {
-            final InputMethodInfo imi = imis.get(i);
-            final List<InputMethodSubtype> subtypes = imm.getEnabledInputMethodSubtypeList(imi,
-                    true);
-            final int subtypeCount = subtypes.size();
-            if (subtypeCount == 0) {
-                ++nonAuxCount;
-            } else {
-                for (int j = 0; j < subtypeCount; ++j) {
-                    final InputMethodSubtype subtype = subtypes.get(j);
-                    if (!subtype.isAuxiliary()) {
-                        ++nonAuxCount;
-                        nonAuxSubtype = subtype;
-                    } else {
-                        ++auxCount;
-                        auxSubtype = subtype;
-                    }
-                }
-            }
-        }
-        if (nonAuxCount > 1 || auxCount > 1) {
-            return true;
-        } else if (nonAuxCount == 1 && auxCount == 1) {
-            if (nonAuxSubtype != null && auxSubtype != null
-                    && (nonAuxSubtype.getLocale().equals(auxSubtype.getLocale())
-                            || auxSubtype.overridesImplicitlyEnabledSubtype()
-                            || nonAuxSubtype.overridesImplicitlyEnabledSubtype())
-                    && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) {
-                return false;
-            }
-            return true;
-        }
-        return false;
-    }
-    void onImeWindowStatusChanged(boolean visible) {
-        InputMethodManager imm =
-                (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
-        List<InputMethodInfo> imis = imm.getInputMethodList();
-
-        mImeState.enabled = (visible && needsToShowImeSwitchOngoingNotification(imm));
-        mImeState.label = getCurrentInputMethodName(mContext, mContext.getContentResolver(),
-                imm, imis, mContext.getPackageManager());
-        if (mImeCallback != null) {
-            mImeCallback.refreshView(mImeTile, mImeState);
-        }
-    }
-    private static String getCurrentInputMethodName(Context context, ContentResolver resolver,
-            InputMethodManager imm, List<InputMethodInfo> imis, PackageManager pm) {
-        if (resolver == null || imis == null) return null;
-        final String currentInputMethodId = Settings.Secure.getString(resolver,
-                Settings.Secure.DEFAULT_INPUT_METHOD);
-        if (TextUtils.isEmpty(currentInputMethodId)) return null;
-        for (InputMethodInfo imi : imis) {
-            if (currentInputMethodId.equals(imi.getId())) {
-                final InputMethodSubtype subtype = imm.getCurrentInputMethodSubtype();
-                final CharSequence summary = subtype != null
-                        ? subtype.getDisplayName(context, imi.getPackageName(),
-                                imi.getServiceInfo().applicationInfo)
-                        : context.getString(R.string.quick_settings_ime_label);
-                return summary.toString();
-            }
-        }
-        return null;
-    }
-
-    // Rotation lock
-    void addRotationLockTile(QuickSettingsTileView view,
-            RotationLockController rotationLockController,
-            RefreshCallback cb) {
-        mRotationLockTile = view;
-        mRotationLockCallback = cb;
-        mRotationLockController = rotationLockController;
-        final int lockOrientation = mRotationLockController.getRotationLockOrientation();
-        mRotationLockedLabel = lockOrientation == Configuration.ORIENTATION_PORTRAIT
-                    ? R.string.quick_settings_rotation_locked_portrait_label
-                    : lockOrientation == Configuration.ORIENTATION_LANDSCAPE
-                    ? R.string.quick_settings_rotation_locked_landscape_label
-                    : R.string.quick_settings_rotation_locked_label;
-        onRotationLockChanged();
-    }
-    void onRotationLockChanged() {
-        onRotationLockStateChanged(mRotationLockController.isRotationLocked(),
-                mRotationLockController.isRotationLockAffordanceVisible());
-    }
-    @Override
-    public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
-        mRotationLockState.visible = affordanceVisible;
-        mRotationLockState.enabled = rotationLocked;
-        mRotationLockState.iconId = rotationLocked
-                ? R.drawable.ic_qs_rotation_locked
-                : R.drawable.ic_qs_auto_rotate;
-        mRotationLockState.label = rotationLocked
-                ? mContext.getString(mRotationLockedLabel)
-                : mContext.getString(R.string.quick_settings_rotation_unlocked_label);
-        mRotationLockCallback.refreshView(mRotationLockTile, mRotationLockState);
-    }
-    void refreshRotationLockTile() {
-        if (mRotationLockTile != null) {
-            onRotationLockChanged();
-        }
-    }
-
-    // Brightness
-    void addBrightnessTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mBrightnessTile = view;
-        mBrightnessCallback = cb;
-        onBrightnessLevelChanged();
-    }
-    @Override
-    public void onBrightnessLevelChanged() {
-        Resources r = mContext.getResources();
-        int mode = Settings.System.getIntForUser(mContext.getContentResolver(),
-                Settings.System.SCREEN_BRIGHTNESS_MODE,
-                Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
-                mUserTracker.getCurrentUserId());
-        mBrightnessState.autoBrightness =
-                (mode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
-        mBrightnessState.iconId = mBrightnessState.autoBrightness
-                ? R.drawable.ic_qs_brightness_auto_on
-                : R.drawable.ic_qs_brightness_auto_off;
-        mBrightnessState.label = r.getString(R.string.quick_settings_brightness_label);
-        mBrightnessCallback.refreshView(mBrightnessTile, mBrightnessState);
-    }
-    void refreshBrightnessTile() {
-        onBrightnessLevelChanged();
-    }
-
-    // Color inversion
-    void addInversionTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mInversionTile = view;
-        mInversionCallback = cb;
-        onInversionChanged();
-    }
-    public void onInversionChanged() {
-        final Resources res = mContext.getResources();
-        final ContentResolver cr = mContext.getContentResolver();
-        final int currentUserId = mUserTracker.getCurrentUserId();
-        final boolean quickSettingEnabled = Settings.Secure.getIntForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_QUICK_SETTING_ENABLED, 0,
-                currentUserId) == 1;
-        final boolean enabled = Settings.Secure.getIntForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, currentUserId) == 1;
-        mInversionState.enabled = quickSettingEnabled;
-        mInversionState.toggled = enabled;
-        // TODO: Add real icon assets.
-        mInversionState.iconId = enabled ? R.drawable.ic_qs_inversion_on
-                : R.drawable.ic_qs_inversion_off;
-        mInversionState.label = res.getString(R.string.quick_settings_inversion_label);
-        mInversionCallback.refreshView(mInversionTile, mInversionState);
-    }
-
-    // Color space adjustment
-    void addColorSpaceTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mColorSpaceTile = view;
-        mColorSpaceCallback = cb;
-        onColorSpaceChanged();
-    }
-    public void onColorSpaceChanged() {
-        final Resources res = mContext.getResources();
-        final ContentResolver cr = mContext.getContentResolver();
-        final int currentUserId = mUserTracker.getCurrentUserId();
-        final boolean quickSettingEnabled = Settings.Secure.getIntForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_QUICK_SETTING_ENABLED, 0,
-                currentUserId) == 1;
-        final boolean enabled = Settings.Secure.getIntForUser(cr,
-                Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, currentUserId) == 1;
-        final int type = Settings.Secure.getIntForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, 0, currentUserId);
-        mColorSpaceState.enabled = quickSettingEnabled;
-        mColorSpaceState.toggled = enabled;
-        mColorSpaceState.type = type;
-        // TODO: Add real icon assets.
-        mColorSpaceState.iconId = enabled ? R.drawable.ic_qs_color_space_on
-                : R.drawable.ic_qs_color_space_off;
-        mColorSpaceState.label = res.getString(R.string.quick_settings_color_space_label);
-        mColorSpaceCallback.refreshView(mColorSpaceTile, mColorSpaceState);
-    }
-
-    // SSL CA Cert warning.
-    public void addSslCaCertWarningTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mSslCaCertWarningTile = view;
-        mSslCaCertWarningCallback = cb;
-        // Set a sane default while we wait for the AsyncTask to finish (no cert).
-        setSslCaCertWarningTileInfo(false, true);
-    }
-    public void setSslCaCertWarningTileInfo(boolean hasCert, boolean isManaged) {
-        Resources r = mContext.getResources();
-        mSslCaCertWarningState.enabled = hasCert;
-        if (isManaged) {
-            mSslCaCertWarningState.iconId = R.drawable.ic_qs_certificate_info;
-        } else {
-            mSslCaCertWarningState.iconId = android.R.drawable.stat_notify_error;
-        }
-        mSslCaCertWarningState.label = r.getString(R.string.ssl_ca_cert_warning);
-        mSslCaCertWarningCallback.refreshView(mSslCaCertWarningTile, mSslCaCertWarningState);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsScrollView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsScrollView.java
deleted file mode 100644
index 175805a..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsScrollView.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2012 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.statusbar.phone;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.ScrollView;
-
-public class QuickSettingsScrollView extends ScrollView {
-
-    public QuickSettingsScrollView(Context context) {
-        super(context);
-    }
-
-    public QuickSettingsScrollView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public QuickSettingsScrollView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    // Y U NO PROTECTED
-    private int getScrollRange() {
-        int scrollRange = 0;
-        if (getChildCount() > 0) {
-            View child = getChildAt(0);
-            scrollRange = Math.max(0,
-                    child.getHeight() - (getHeight() - getPaddingBottom() - getPaddingTop()));
-        }
-        return scrollRange;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        final int range = getScrollRange();
-        if (range == 0) {
-            return false;
-        }
-
-        return super.onTouchEvent(ev);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
deleted file mode 100644
index ad18294..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2012 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.statusbar.phone;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewParent;
-import android.widget.FrameLayout;
-
-/**
- *
- */
-class QuickSettingsTileView extends FrameLayout {
-    private static final String TAG = "QuickSettingsTileView";
-
-    private int mContentLayoutId;
-    private int mColSpan;
-    private boolean mPrepared;
-    private OnPrepareListener mOnPrepareListener;
-
-    public QuickSettingsTileView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        mContentLayoutId = -1;
-        mColSpan = 1;
-    }
-
-    void setColumnSpan(int span) {
-        mColSpan = span;
-    }
-
-    int getColumnSpan() {
-        return mColSpan;
-    }
-
-    void setContent(int layoutId, LayoutInflater inflater) {
-        mContentLayoutId = layoutId;
-        inflater.inflate(layoutId, this);
-    }
-
-    void reinflateContent(LayoutInflater inflater) {
-        if (mContentLayoutId != -1) {
-            removeAllViews();
-            setContent(mContentLayoutId, inflater);
-        } else {
-            Log.e(TAG, "Not reinflating content: No layoutId set");
-        }
-    }
-
-    @Override
-    public void setVisibility(int vis) {
-        if (QuickSettings.DEBUG_GONE_TILES) {
-            if (vis == View.GONE) {
-                vis = View.VISIBLE;
-                setAlpha(0.25f);
-                setEnabled(false);
-            } else {
-                setAlpha(1f);
-                setEnabled(true);
-            }
-        }
-        super.setVisibility(vis);
-    }
-
-    public void setOnPrepareListener(OnPrepareListener listener) {
-        if (mOnPrepareListener != listener) {
-            mOnPrepareListener = listener;
-            mPrepared = false;
-            post(new Runnable() {
-                @Override
-                public void run() {
-                    updatePreparedState();
-                }
-            });
-        }
-    }
-
-    @Override
-    protected void onVisibilityChanged(View changedView, int visibility) {
-        super.onVisibilityChanged(changedView, visibility);
-        updatePreparedState();
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        updatePreparedState();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        updatePreparedState();
-    }
-
-    private void updatePreparedState() {
-        if (mOnPrepareListener != null) {
-            if (isParentVisible()) {
-                if (!mPrepared) {
-                    mPrepared = true;
-                    mOnPrepareListener.onPrepare();
-                }
-            } else if (mPrepared) {
-                mPrepared = false;
-                mOnPrepareListener.onUnprepare();
-            }
-        }
-    }
-
-    private boolean isParentVisible() {
-        if (!isAttachedToWindow()) {
-            return false;
-        }
-        for (ViewParent current = getParent(); current instanceof View;
-                current = current.getParent()) {
-            View view = (View)current;
-            if (view.getVisibility() != VISIBLE) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Called when the view's parent becomes visible or invisible to provide
-     * an opportunity for the client to provide new content.
-     */
-    public interface OnPrepareListener {
-        void onPrepare();
-        void onUnprepare();
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 5527473..2305445 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -28,6 +28,7 @@
 import android.widget.RelativeLayout;
 
 import com.android.systemui.R;
+import com.android.systemui.qs.QSPanel;
 import com.android.systemui.settings.BrightnessController;
 import com.android.systemui.settings.ToggleSlider;
 import com.android.systemui.statusbar.policy.UserInfoController;
@@ -60,6 +61,7 @@
 
     private ActivityStarter mActivityStarter;
     private BrightnessController mBrightnessController;
+    private QSPanel mQSPanel;
 
     private final Rect mClipBounds = new Rect();
     private final Outline mOutline = new Outline();
@@ -115,6 +117,9 @@
             updateVisibilities();
             updateSystemIconsLayoutParams();
             updateBrightnessControllerState();
+            if (mQSPanel != null) {
+                mQSPanel.setExpanded(expanded);
+            }
         }
     }
 
@@ -259,4 +264,8 @@
     private void startSettingsActivity() {
         mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS));
     }
+
+    public void setQSPanel(QSPanel qsp) {
+        mQSPanel = qsp;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
deleted file mode 100644
index ff921cd..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * 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.statusbar.phone;
-
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.Typeface;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.OvalShape;
-import android.text.Spannable;
-import android.text.SpannableStringBuilder;
-import android.text.TextPaint;
-import android.text.method.LinkMovementMethod;
-import android.text.style.URLSpan;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
-import android.widget.Switch;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.ZenModeView.Adapter.ExitCondition;
-
-public class ZenModeView extends RelativeLayout {
-    private static final String TAG = ZenModeView.class.getSimpleName();
-    private static final boolean DEBUG = false;
-
-    public static final int BACKGROUND = 0xff282828;
-
-    private static final Typeface CONDENSED =
-            Typeface.create("sans-serif-condensed", Typeface.NORMAL);
-    private static final int GRAY = 0xff999999; //TextAppearance.StatusBar.Expanded.Network
-    private static final int DARK_GRAY = 0xff333333;
-
-    private static final long DURATION = new ValueAnimator().getDuration();
-    private static final long PAGER_DURATION = DURATION / 2;
-    private static final long CLOSE_DELAY = 600;
-    private static final long AUTO_ACTIVATE_DELAY = 100;
-
-    private final Context mContext;
-    private final TextView mModeText;
-    private final Switch mModeSwitch;
-    private final View mDivider;
-    private final UntilPager mUntilPager;
-    private final ProgressDots mProgressDots;
-    private final View mDivider2;
-    private final TextView mSettingsButton;
-
-    private Adapter mAdapter;
-    private boolean mInit;
-    private boolean mAutoActivate;
-
-    public ZenModeView(Context context) {
-        this(context, null);
-    }
-
-    public ZenModeView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        if (DEBUG) log("new %s()", getClass().getSimpleName());
-        mContext = context;
-
-        final int iconSize = mContext.getResources()
-                .getDimensionPixelSize(com.android.internal.R.dimen.notification_large_icon_width);
-        final int topRowSize = iconSize * 2 / 3;
-        final int p = topRowSize / 3;
-
-        LayoutParams lp = null;
-
-        mModeText = new TextView(mContext);
-        mModeText.setText(R.string.zen_mode_title);
-        mModeText.setId(android.R.id.title);
-        mModeText.setTextColor(GRAY);
-        mModeText.setTypeface(CONDENSED);
-        mModeText.setAllCaps(true);
-        mModeText.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
-        mModeText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mModeText.getTextSize() * 1.5f);
-        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize);
-        lp.leftMargin = p;
-        addView(mModeText, lp);
-
-        mModeSwitch = new Switch(mContext);
-        mModeSwitch.setSwitchPadding(0);
-        mModeSwitch.setSwitchTypeface(CONDENSED);
-        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize);
-        lp.topMargin = p;
-        lp.rightMargin = p;
-        lp.addRule(ALIGN_PARENT_RIGHT);
-        lp.addRule(ALIGN_BASELINE, mModeText.getId());
-        addView(mModeSwitch, lp);
-        mModeSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
-            @Override
-            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-                mAdapter.setMode(isChecked);
-                if (!mInit) return;
-                postDelayed(new Runnable(){
-                    @Override
-                    public void run() {
-                        mAdapter.close();
-                    }
-                }, CLOSE_DELAY);
-            }
-        });
-
-        mDivider = new View(mContext);
-        mDivider.setId(android.R.id.empty);
-        mDivider.setBackgroundColor(GRAY);
-        lp = new LayoutParams(LayoutParams.MATCH_PARENT, 2);
-        lp.addRule(BELOW, mModeText.getId());
-        lp.bottomMargin = p;
-        addView(mDivider, lp);
-
-        mUntilPager = new UntilPager(mContext, iconSize * 3 / 4);
-        mUntilPager.setId(android.R.id.tabhost);
-        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
-        lp.leftMargin = lp.rightMargin = iconSize / 2;
-        lp.addRule(CENTER_HORIZONTAL);
-        lp.addRule(BELOW, mDivider.getId());
-        addView(mUntilPager, lp);
-
-        mProgressDots = new ProgressDots(mContext, iconSize / 5);
-        mProgressDots.setId(android.R.id.progress);
-        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
-        lp.addRule(CENTER_HORIZONTAL);
-        lp.addRule(BELOW, mUntilPager.getId());
-        addView(mProgressDots, lp);
-
-        mDivider2 = new View(mContext);
-        mDivider2.setId(android.R.id.widget_frame);
-        mDivider2.setBackgroundColor(GRAY);
-        lp = new LayoutParams(LayoutParams.MATCH_PARENT, 2);
-        lp.addRule(BELOW, mProgressDots.getId());
-        addView(mDivider2, lp);
-
-        mSettingsButton = new TextView(mContext);
-        mSettingsButton.setTypeface(CONDENSED);
-        mSettingsButton.setTextSize(TypedValue.COMPLEX_UNIT_PX, mSettingsButton.getTextSize() * 1.3f);
-        mSettingsButton.setPadding(p, p, p, p);
-        mSettingsButton.setText("More settings...");
-        lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
-        lp.addRule(BELOW, mDivider2.getId());
-        addView(mSettingsButton, lp);
-        mSettingsButton.setOnTouchListener(new OnTouchListener() {
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-                if (event.getAction() == MotionEvent.ACTION_DOWN) {
-                    mSettingsButton.setBackgroundColor(DARK_GRAY);
-                } else if (event.getAction() == MotionEvent.ACTION_UP) {
-                    mSettingsButton.setBackground(null);
-                    if (mAdapter != null) {
-                        mAdapter.configure();
-                    }
-                }
-                return true;
-            }
-        });
-    }
-
-    public void setAdapter(Adapter adapter) {
-        mAdapter = adapter;
-        mAdapter.setCallbacks(new Adapter.Callbacks() {
-            @Override
-            public void onChanged() {
-                post(new Runnable() {
-                    @Override
-                    public void run() {
-                        updateState(true);
-                    }
-                });
-            }
-        });
-        updateState(false);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        if (mAutoActivate) {
-            mAutoActivate = false;
-            postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    if (!mModeSwitch.isChecked()) {
-                        mInit = false;
-                        mModeSwitch.setChecked(true);
-                    }
-                }
-            }, AUTO_ACTIVATE_DELAY);
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        if (mAdapter != null) {
-            mAdapter.dispose();
-        }
-    }
-
-    public void setAutoActivate(boolean value) {
-        mAutoActivate = value;
-    }
-
-    private void updateState(boolean animate) {
-        mUntilPager.updateState();
-        mModeSwitch.setChecked(mAdapter.getMode());
-        mInit = true;
-    }
-
-    private static void log(String msg, Object... args) {
-        Log.d(TAG, args == null || args.length == 0 ? msg : String.format(msg, args));
-    }
-
-    private final class UntilView extends FrameLayout {
-        private static final boolean SUPPORT_LINKS = false;
-
-        private final TextView mText;
-        public UntilView(Context context) {
-            super(context);
-            mText = new TextView(mContext);
-            mText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mText.getTextSize() * 1.3f);
-            mText.setTypeface(CONDENSED);
-            mText.setTextColor(GRAY);
-            mText.setGravity(Gravity.CENTER);
-            addView(mText);
-        }
-
-        public void setExitCondition(final ExitCondition ec) {
-            SpannableStringBuilder ss = new SpannableStringBuilder(ec.summary);
-            if (SUPPORT_LINKS && ec.action != null) {
-                ss.setSpan(new CustomLinkSpan() {
-                    @Override
-                    public void onClick() {
-                        // TODO wire up links
-                        Toast.makeText(mContext, ec.action, Toast.LENGTH_SHORT).show();
-                    }
-                }, 0, ss.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
-                mText.setMovementMethod(LinkMovementMethod.getInstance());
-            } else {
-                mText.setMovementMethod(null);
-            }
-            mText.setText(ss);
-        }
-    }
-
-    private final class ProgressDots extends LinearLayout {
-        private final int mDotSize;
-        public ProgressDots(Context context, int dotSize) {
-            super(context);
-            setOrientation(HORIZONTAL);
-            mDotSize = dotSize;
-        }
-
-        private void updateState(int current, int count) {
-            while (getChildCount() < count) {
-                View dot = new View(mContext);
-                OvalShape s = new OvalShape();
-                ShapeDrawable sd = new ShapeDrawable(s);
-
-                dot.setBackground(sd);
-                LayoutParams lp = new LayoutParams(mDotSize, mDotSize);
-                lp.leftMargin = lp.rightMargin = mDotSize / 2;
-                lp.topMargin = lp.bottomMargin = mDotSize * 2 / 3;
-                addView(dot, lp);
-            }
-            while (getChildCount() > count) {
-                removeViewAt(getChildCount() - 1);
-            }
-            final int N = getChildCount();
-            for (int i = 0; i < N; i++) {
-                final int color = current == i ? GRAY : DARK_GRAY;
-                ((ShapeDrawable)getChildAt(i).getBackground()).setColorFilter(color, Mode.ADD);
-            }
-        }
-    }
-
-    private final class UntilPager extends RelativeLayout {
-        private final UntilView[] mViews;
-        private int mCurrent;
-        private float mDownX;
-
-        public UntilPager(Context context, int iconSize) {
-            super(context);
-            mViews = new UntilView[3];
-            for (int i = 0; i < mViews.length; i++) {
-                UntilView v = new UntilView(mContext);
-                LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, iconSize);
-                addView(v, lp);
-                mViews[i] = v;
-            }
-            updateState();
-            addOnLayoutChangeListener(new OnLayoutChangeListener() {
-                @Override
-                public void onLayoutChange(View v, int left, int top, int right,
-                        int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
-                    if (left != oldLeft || right != oldRight) {
-                        updateState();
-                    }
-                }
-            });
-            setBackgroundColor(DARK_GRAY);
-        }
-
-        private void updateState() {
-            if (mAdapter == null) {
-                return;
-            }
-            UntilView current = mViews[mCurrent];
-            current.setExitCondition(mAdapter.getExitCondition(0));
-            UntilView next = mViews[mCurrent + 1 % 3];
-            next.setExitCondition(mAdapter.getExitCondition(1));
-            UntilView prev = mViews[mCurrent + 2 % 3];
-            prev.setExitCondition(mAdapter.getExitCondition(-1));
-            position(0, false);
-            mProgressDots.updateState(mAdapter.getExitConditionIndex(),
-                    mAdapter.getExitConditionCount());
-        }
-
-        private void position(float dx, boolean animate) {
-            int w = getWidth();
-            UntilView current = mViews[mCurrent];
-            UntilView next = mViews[mCurrent + 1 % 3];
-            UntilView prev = mViews[mCurrent + 2 % 3];
-            if (animate) {
-                current.animate().setDuration(PAGER_DURATION).translationX(dx).start();
-                next.animate().setDuration(PAGER_DURATION).translationX(w + dx).start();
-                prev.animate().setDuration(PAGER_DURATION).translationX(-w + dx).start();
-            } else {
-                current.setTranslationX(dx);
-                next.setTranslationX(w + dx);
-                prev.setTranslationX(-w + dx);
-            }
-        }
-
-        @Override
-        public boolean onTouchEvent(MotionEvent event) {
-            if (DEBUG) log("onTouchEvent " + MotionEvent.actionToString(event.getAction()));
-            if (event.getAction() == MotionEvent.ACTION_DOWN) {
-                mDownX = event.getX();
-            } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
-                float dx = event.getX() - mDownX;
-                position(dx, false);
-            } else if (event.getAction() == MotionEvent.ACTION_UP
-                    || event.getAction() == MotionEvent.ACTION_CANCEL) {
-                float dx = event.getX() - mDownX;
-                int d = Math.abs(dx) < getWidth() / 3 ? 0 : Math.signum(dx) > 0 ? -1 : 1;
-                if (d != 0 && mAdapter.getExitConditionCount() > 1) {
-                    mAdapter.select(mAdapter.getExitCondition(d));
-                } else {
-                    position(0, true);
-                }
-            }
-            return true;
-        }
-    }
-
-    private abstract static class CustomLinkSpan extends URLSpan {
-        abstract public void onClick();
-
-        public CustomLinkSpan() {
-            super("#");
-        }
-
-        @Override
-        public void updateDrawState(TextPaint ds) {
-            super.updateDrawState(ds);
-            ds.setUnderlineText(false);
-            ds.bgColor = BACKGROUND;
-        }
-
-        @Override
-        public void onClick(View widget) {
-            onClick();
-        }
-    }
-
-    public interface Adapter {
-        void configure();
-        void close();
-        boolean getMode();
-        void setMode(boolean mode);
-        void select(ExitCondition ec);
-        void init();
-        void dispose();
-        void setCallbacks(Callbacks callbacks);
-        ExitCondition getExitCondition(int d);
-        int getExitConditionCount();
-        int getExitConditionIndex();
-
-        public static class ExitCondition {
-            public String summary;
-            public String line1;
-            public String line2;
-            public String action;
-            public Object tag;
-        }
-
-        public interface Callbacks {
-            void onChanged();
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
deleted file mode 100644
index 8748888..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * 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.statusbar.phone;
-
-import android.app.INotificationManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.provider.Settings;
-import android.service.notification.Condition;
-import android.service.notification.IConditionListener;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public abstract class ZenModeViewAdapter implements ZenModeView.Adapter {
-    private static final String TAG = "ZenModeViewAdapter";
-
-    private final Context mContext;
-    private final ContentResolver mResolver;
-    private final Handler mHandler = new Handler();
-    private final SettingsObserver mObserver;
-    private final List<ExitCondition> mExits = new ArrayList<ExitCondition>(Arrays.asList(
-            newExit("Until you turn this off", "Until", "You turn this off", null)));
-    private final INotificationManager mNoMan;
-    private final ArrayMap<Uri, Condition> mConditions = new ArrayMap<Uri, Condition>();
-
-    private Callbacks mCallbacks;
-    private int mExitIndex;
-    private boolean mMode;
-
-    public ZenModeViewAdapter(Context context) {
-        mContext = context;
-        mResolver = mContext.getContentResolver();
-        mObserver = new SettingsObserver(mHandler);
-        mNoMan = INotificationManager.Stub.asInterface(
-                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
-        try {
-            mNoMan.requestZenModeConditions(mListener, Condition.FLAG_RELEVANT_NOW);
-        } catch (RemoteException e) {
-            // noop
-        }
-        mObserver.init();
-        init();
-    }
-
-    @Override
-    public boolean getMode() {
-        return mMode;
-    }
-
-    @Override
-    public void setMode(boolean mode) {
-        if (mode == mMode) return;
-        mMode = mode;
-        final int v = mMode ? Settings.Global.ZEN_MODE_ON : Settings.Global.ZEN_MODE_OFF;
-        AsyncTask.execute(new Runnable() {
-            @Override
-            public void run() {
-                Settings.Global.putInt(mContext.getContentResolver(),
-                        Settings.Global.ZEN_MODE, v);
-            }
-        });
-        dispatchChanged();
-    }
-
-    @Override
-    public void init() {
-        if (mExitIndex != 0) {
-            mExitIndex = 0;
-            dispatchChanged();
-        }
-        setZenModeCondition();
-    }
-
-    @Override
-    public void dispose() {
-        try {
-            mNoMan.requestZenModeConditions(mListener, 0 /*none*/);
-        } catch (RemoteException e) {
-            // noop
-        }
-    }
-
-    private void dispatchChanged() {
-        mHandler.removeCallbacks(mChanged);
-        mHandler.post(mChanged);
-    }
-
-    @Override
-    public void setCallbacks(final Callbacks callbacks) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mCallbacks = callbacks;
-            }
-        });
-    }
-
-    @Override
-    public ExitCondition getExitCondition(int d) {
-        final int n = mExits.size();
-        final int i = (n + (mExitIndex + (int)Math.signum(d))) % n;
-        return mExits.get(i);
-    }
-
-    @Override
-    public int getExitConditionCount() {
-        return mExits.size();
-    }
-
-    @Override
-    public int getExitConditionIndex() {
-        return mExitIndex;
-    }
-
-    @Override
-    public void select(ExitCondition ec) {
-        final int i = mExits.indexOf(ec);
-        if (i == -1 || i == mExitIndex) {
-            return;
-        }
-        mExitIndex = i;
-        dispatchChanged();
-        setZenModeCondition();
-    }
-
-    private void setZenModeCondition() {
-        if (mExitIndex < 0 || mExitIndex >= mExits.size()) {
-            Log.w(TAG, "setZenModeCondition to bad index " + mExitIndex + " of " + mExits.size());
-            return;
-        }
-        final Uri conditionUri = (Uri) mExits.get(mExitIndex).tag;
-        try {
-            mNoMan.setZenModeCondition(conditionUri);
-        } catch (RemoteException e) {
-            // noop
-        }
-    }
-
-    private static ExitCondition newExit(String summary, String line1, String line2, Object tag) {
-        final ExitCondition rt = new ExitCondition();
-        rt.summary = summary;
-        rt.line1 = line1;
-        rt.line2 = line2;
-        rt.tag = tag;
-        return rt;
-    }
-
-    private final Runnable mChanged = new Runnable() {
-        public void run() {
-            if (mCallbacks == null) {
-                return;
-            }
-            try {
-                mCallbacks.onChanged();
-            } catch (Throwable t) {
-                Log.w(TAG, "Error dispatching onChanged to " + mCallbacks, t);
-            }
-        }
-    };
-
-    private final class SettingsObserver extends ContentObserver {
-        public SettingsObserver(Handler handler) {
-            super(handler);
-        }
-
-        public void init() {
-            loadSettings();
-            mResolver.registerContentObserver(
-                    Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
-                    false, this);
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            loadSettings();
-            mChanged.run();  // already on handler
-        }
-
-        private void loadSettings() {
-            mMode = getModeFromSetting();
-        }
-
-        private boolean getModeFromSetting() {
-            final int v = Settings.Global.getInt(mResolver,
-                    Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
-            return v != Settings.Global.ZEN_MODE_OFF;
-        }
-    }
-
-    private final IConditionListener mListener = new IConditionListener.Stub() {
-        @Override
-        public void onConditionsReceived(Condition[] conditions) {
-            if (conditions == null || conditions.length == 0) return;
-            for (Condition c : conditions) {
-                mConditions.put(c.id, c);
-            }
-            for (int i = mExits.size() - 1; i > 0; i--) {
-                mExits.remove(i);
-            }
-            for (Condition c : mConditions.values()) {
-                mExits.add(newExit(c.summary, c.line1, c.line2, c.id));
-            }
-            dispatchChanged();
-        }
-    };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index 0e53f0d..f4145cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * 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.
@@ -16,87 +16,14 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
-import android.bluetooth.BluetoothDevice;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
+public interface BluetoothController {
+    void addStateChangedCallback(BluetoothStateChangeCallback callback);
+    void removeStateChangedCallback(BluetoothStateChangeCallback callback);
 
-public class BluetoothController extends BroadcastReceiver {
-    private static final String TAG = "StatusBar.BluetoothController";
-
-    private boolean mEnabled = false;
-
-    private Set<BluetoothDevice> mBondedDevices = new HashSet<BluetoothDevice>();
-
-    private ArrayList<BluetoothStateChangeCallback> mChangeCallbacks =
-            new ArrayList<BluetoothStateChangeCallback>();
-
-    public BluetoothController(Context context) {
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
-        filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
-        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
-        context.registerReceiver(this, filter);
-
-        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        if (adapter != null) {
-            handleAdapterStateChange(adapter.getState());
-        }
-        fireCallbacks();
-        updateBondedBluetoothDevices();
-    }
-
-    public void addStateChangedCallback(BluetoothStateChangeCallback cb) {
-        mChangeCallbacks.add(cb);
-    }
-
-    public Set<BluetoothDevice> getBondedBluetoothDevices() {
-        return mBondedDevices;
-    }
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        final String action = intent.getAction();
-
-        if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
-            handleAdapterStateChange(
-                    intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR));
-        }
-        fireCallbacks();
-        updateBondedBluetoothDevices();
-    }
-
-    private void updateBondedBluetoothDevices() {
-        mBondedDevices.clear();
-
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        if (adapter != null) {
-            Set<BluetoothDevice> devices = adapter.getBondedDevices();
-            if (devices != null) {
-                for (BluetoothDevice device : devices) {
-                    if (device.getBondState() != BluetoothDevice.BOND_NONE) {
-                        mBondedDevices.add(device);
-                    }
-                }
-            }
-        }
-    }
-
-    private void handleAdapterStateChange(int adapterState) {
-        mEnabled = (adapterState == BluetoothAdapter.STATE_ON);
-    }
-
-    private void fireCallbacks() {
-        for (BluetoothStateChangeCallback cb : mChangeCallbacks) {
-            cb.onBluetoothStateChange(mEnabled);
-        }
-    }
+    boolean isBluetoothSupported();
+    boolean isBluetoothEnabled();
+    boolean isBluetoothConnected();
+    void setBluetoothEnabled(boolean enabled);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
new file mode 100644
index 0000000..1c7119f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2008 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.statusbar.policy;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+public class BluetoothControllerImpl extends BroadcastReceiver implements BluetoothController {
+    private static final String TAG = "StatusBar.BluetoothController";
+
+    private final BluetoothAdapter mAdapter;
+
+    private boolean mEnabled = false;
+
+    private Set<BluetoothDevice> mBondedDevices = new HashSet<BluetoothDevice>();
+
+    private ArrayList<BluetoothStateChangeCallback> mChangeCallbacks =
+            new ArrayList<BluetoothStateChangeCallback>();
+
+    public BluetoothControllerImpl(Context context) {
+        mAdapter = BluetoothAdapter.getDefaultAdapter();
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+        filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
+        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+        context.registerReceiver(this, filter);
+
+        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter != null) {
+            handleAdapterStateChange(adapter.getState());
+        }
+        fireCallbacks();
+        updateBondedBluetoothDevices();
+    }
+
+    public void addStateChangedCallback(BluetoothStateChangeCallback cb) {
+        mChangeCallbacks.add(cb);
+    }
+
+    @Override
+    public void removeStateChangedCallback(BluetoothStateChangeCallback cb) {
+        mChangeCallbacks.remove(cb);
+    }
+
+    @Override
+    public boolean isBluetoothEnabled() {
+        return mAdapter != null && mAdapter.isEnabled();
+    }
+
+    @Override
+    public boolean isBluetoothConnected() {
+        return mAdapter != null
+                && mAdapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED;
+    }
+
+    @Override
+    public void setBluetoothEnabled(boolean enabled) {
+        if (mAdapter != null) {
+            if (enabled) {
+                mAdapter.enable();
+            } else {
+                mAdapter.disable();
+            }
+        }
+    }
+
+    @Override
+    public boolean isBluetoothSupported() {
+        return mAdapter != null;
+    }
+
+    public Set<BluetoothDevice> getBondedBluetoothDevices() {
+        return mBondedDevices;
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        final String action = intent.getAction();
+
+        if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
+            handleAdapterStateChange(
+                    intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR));
+        }
+        fireCallbacks();
+        updateBondedBluetoothDevices();
+    }
+
+    private void updateBondedBluetoothDevices() {
+        mBondedDevices.clear();
+
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter != null) {
+            Set<BluetoothDevice> devices = adapter.getBondedDevices();
+            if (devices != null) {
+                for (BluetoothDevice device : devices) {
+                    if (device.getBondState() != BluetoothDevice.BOND_NONE) {
+                        mBondedDevices.add(device);
+                    }
+                }
+            }
+        }
+    }
+
+    private void handleAdapterStateChange(int adapterState) {
+        mEnabled = (adapterState == BluetoothAdapter.STATE_ON);
+    }
+
+    private void fireCallbacks() {
+        for (BluetoothStateChangeCallback cb : mChangeCallbacks) {
+            cb.onBluetoothStateChange(mEnabled);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
new file mode 100644
index 0000000..54041e1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
@@ -0,0 +1,28 @@
+/*
+ * 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.statusbar.policy;
+
+public interface CastController {
+    void addCallback(Callback callback);
+    void removeCallback(Callback callback);
+    void setDiscovering(boolean request);
+    void setCurrentUserId(int currentUserId);
+
+    public interface Callback {
+        void onStateChanged(boolean enabled, boolean connecting, String connectedRouteName);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
new file mode 100644
index 0000000..33a85b1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
@@ -0,0 +1,110 @@
+/*
+ * 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.statusbar.policy;
+
+import android.content.Context;
+import android.media.MediaRouter;
+import android.media.MediaRouter.RouteInfo;
+
+import java.util.ArrayList;
+
+/** Platform implementation of the cast controller. **/
+public class CastControllerImpl implements CastController {
+
+    private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
+    private final MediaRouter mMediaRouter;
+
+    public CastControllerImpl(Context context) {
+        mMediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+    }
+
+    @Override
+    public void addCallback(Callback callback) {
+        mCallbacks.add(callback);
+    }
+
+    @Override
+    public void removeCallback(Callback callback) {
+        mCallbacks.remove(callback);
+    }
+
+    @Override
+    public void setDiscovering(boolean request) {
+        if (request) {
+            mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+                    mMediaCallback,
+                    MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
+        } else {
+            mMediaRouter.removeCallback(mMediaCallback);
+        }
+    }
+
+    @Override
+    public void setCurrentUserId(int currentUserId) {
+        mMediaRouter.rebindAsUser(currentUserId);
+    }
+
+    private void updateRemoteDisplays() {
+        final MediaRouter.RouteInfo connectedRoute = mMediaRouter.getSelectedRoute(
+                MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
+        boolean enabled = connectedRoute != null
+                && connectedRoute.matchesTypes(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
+        boolean connecting;
+        if (enabled) {
+            connecting = connectedRoute.isConnecting();
+        } else {
+            connecting = false;
+            enabled = mMediaRouter.isRouteAvailable(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+                    MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE);
+        }
+
+        String connectedRouteName = null;
+        if (connectedRoute != null) {
+            connectedRouteName = connectedRoute.getName().toString();
+        }
+        fireStateChanged(enabled, connecting, connectedRouteName);
+    }
+
+    private void fireStateChanged(boolean enabled, boolean connecting, String connectedRouteName) {
+        for (Callback callback : mCallbacks) {
+            callback.onStateChanged(enabled, connecting, connectedRouteName);
+        }
+    }
+
+    private final MediaRouter.SimpleCallback mMediaCallback = new MediaRouter.SimpleCallback() {
+        @Override
+        public void onRouteAdded(MediaRouter router, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+        @Override
+        public void onRouteChanged(MediaRouter router, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+        @Override
+        public void onRouteRemoved(MediaRouter router, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+        @Override
+        public void onRouteSelected(MediaRouter router, int type, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+        @Override
+        public void onRouteUnselected(MediaRouter router, int type, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java
new file mode 100644
index 0000000..158e9c1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java
@@ -0,0 +1,22 @@
+/*
+ * 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.statusbar.policy;
+
+/** Common interface for items requiring manual cleanup. **/
+public interface Disposable {
+    void dispose();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index f5ee95b..29a8981 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * 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.
@@ -16,47 +16,11 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.app.ActivityManager;
-import android.app.AppOpsManager;
-import android.app.StatusBarManager;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.location.LocationManager;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-
-import com.android.systemui.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A controller to manage changes of location related states and update the views accordingly.
- */
-public class LocationController extends BroadcastReceiver {
-    // The name of the placeholder corresponding to the location request status icon.
-    // This string corresponds to config_statusBarIcons in core/res/res/values/config.xml.
-    public static final String LOCATION_STATUS_ICON_PLACEHOLDER = "location";
-    public static final int LOCATION_STATUS_ICON_ID
-        = R.drawable.stat_sys_device_access_location_found;
-
-    private static final int[] mHighPowerRequestAppOpArray
-        = new int[] {AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION};
-
-    private Context mContext;
-
-    private AppOpsManager mAppOpsManager;
-    private StatusBarManager mStatusBarManager;
-
-    private boolean mAreActiveLocationRequests;
-
-    private ArrayList<LocationSettingsChangeCallback> mSettingsChangeCallbacks =
-            new ArrayList<LocationSettingsChangeCallback>();
+public interface LocationController {
+    boolean isLocationEnabled();
+    boolean setLocationEnabled(boolean enabled);
+    void addSettingsChangedCallback(LocationSettingsChangeCallback cb);
+    void removeSettingsChangedCallback(LocationSettingsChangeCallback cb);
 
     /**
      * A callback for change in location settings (the user has enabled/disabled location).
@@ -68,156 +32,6 @@
          * @param locationEnabled A value of true indicates that at least one type of location
          *                        is enabled in settings.
          */
-        public void onLocationSettingsChanged(boolean locationEnabled);
-    }
-
-    public LocationController(Context context) {
-        mContext = context;
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
-        context.registerReceiver(this, filter);
-
-        mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
-        mStatusBarManager
-                = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
-
-        // Register to listen for changes in location settings.
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION);
-        context.registerReceiverAsUser(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                String action = intent.getAction();
-                if (LocationManager.MODE_CHANGED_ACTION.equals(action)) {
-                    locationSettingsChanged();
-                }
-            }
-        }, UserHandle.ALL, intentFilter, null, new Handler());
-
-        // Examine the current location state and initialize the status view.
-        updateActiveLocationRequests();
-        refreshViews();
-    }
-
-    /**
-     * Add a callback to listen for changes in location settings.
-     */
-    public void addSettingsChangedCallback(LocationSettingsChangeCallback cb) {
-        mSettingsChangeCallbacks.add(cb);
-    }
-
-    /**
-     * Enable or disable location in settings.
-     *
-     * <p>This will attempt to enable/disable every type of location setting
-     * (e.g. high and balanced power).
-     *
-     * <p>If enabling, a user consent dialog will pop up prompting the user to accept.
-     * If the user doesn't accept, network location won't be enabled.
-     *
-     * @return true if attempt to change setting was successful.
-     */
-    public boolean setLocationEnabled(boolean enabled) {
-        int currentUserId = ActivityManager.getCurrentUser();
-        if (isUserLocationRestricted(currentUserId)) {
-            return false;
-        }
-        final ContentResolver cr = mContext.getContentResolver();
-        // When enabling location, a user consent dialog will pop up, and the
-        // setting won't be fully enabled until the user accepts the agreement.
-        int mode = enabled
-                ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY : Settings.Secure.LOCATION_MODE_OFF;
-        // QuickSettings always runs as the owner, so specifically set the settings
-        // for the current foreground user.
-        return Settings.Secure
-                .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId);
-    }
-
-    /**
-     * Returns true if location isn't disabled in settings.
-     */
-    public boolean isLocationEnabled() {
-        ContentResolver resolver = mContext.getContentResolver();
-        // QuickSettings always runs as the owner, so specifically retrieve the settings
-        // for the current foreground user.
-        int mode = Settings.Secure.getIntForUser(resolver, Settings.Secure.LOCATION_MODE,
-                Settings.Secure.LOCATION_MODE_OFF, ActivityManager.getCurrentUser());
-        return mode != Settings.Secure.LOCATION_MODE_OFF;
-    }
-
-    /**
-     * Returns true if the current user is restricted from using location.
-     */
-    private boolean isUserLocationRestricted(int userId) {
-        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        return um.hasUserRestriction(
-                UserManager.DISALLOW_SHARE_LOCATION,
-                new UserHandle(userId));
-    }
-
-    /**
-     * Returns true if there currently exist active high power location requests.
-     */
-    private boolean areActiveHighPowerLocationRequests() {
-        List<AppOpsManager.PackageOps> packages
-            = mAppOpsManager.getPackagesForOps(mHighPowerRequestAppOpArray);
-        // AppOpsManager can return null when there is no requested data.
-        if (packages != null) {
-            final int numPackages = packages.size();
-            for (int packageInd = 0; packageInd < numPackages; packageInd++) {
-                AppOpsManager.PackageOps packageOp = packages.get(packageInd);
-                List<AppOpsManager.OpEntry> opEntries = packageOp.getOps();
-                if (opEntries != null) {
-                    final int numOps = opEntries.size();
-                    for (int opInd = 0; opInd < numOps; opInd++) {
-                        AppOpsManager.OpEntry opEntry = opEntries.get(opInd);
-                        // AppOpsManager should only return OP_MONITOR_HIGH_POWER_LOCATION because
-                        // of the mHighPowerRequestAppOpArray filter, but checking defensively.
-                        if (opEntry.getOp() == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION) {
-                            if (opEntry.isRunning()) {
-                                return true;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        return false;
-    }
-
-    // Updates the status view based on the current state of location requests.
-    private void refreshViews() {
-        if (mAreActiveLocationRequests) {
-            mStatusBarManager.setIcon(LOCATION_STATUS_ICON_PLACEHOLDER, LOCATION_STATUS_ICON_ID, 0,
-                    mContext.getString(R.string.accessibility_location_active));
-        } else {
-            mStatusBarManager.removeIcon(LOCATION_STATUS_ICON_PLACEHOLDER);
-        }
-    }
-
-    // Reads the active location requests and updates the status view if necessary.
-    private void updateActiveLocationRequests() {
-        boolean hadActiveLocationRequests = mAreActiveLocationRequests;
-        mAreActiveLocationRequests = areActiveHighPowerLocationRequests();
-        if (mAreActiveLocationRequests != hadActiveLocationRequests) {
-            refreshViews();
-        }
-    }
-
-    private void locationSettingsChanged() {
-        boolean isEnabled = isLocationEnabled();
-        for (LocationSettingsChangeCallback cb : mSettingsChangeCallbacks) {
-            cb.onLocationSettingsChanged(isEnabled);
-        }
-    }
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        final String action = intent.getAction();
-        if (LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) {
-            updateActiveLocationRequests();
-        }
+        void onLocationSettingsChanged(boolean locationEnabled);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
new file mode 100644
index 0000000..9e5ad18
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2008 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.statusbar.policy;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.location.LocationManager;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+
+import com.android.systemui.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A controller to manage changes of location related states and update the views accordingly.
+ */
+public class LocationControllerImpl extends BroadcastReceiver implements LocationController {
+    // The name of the placeholder corresponding to the location request status icon.
+    // This string corresponds to config_statusBarIcons in core/res/res/values/config.xml.
+    public static final String LOCATION_STATUS_ICON_PLACEHOLDER = "location";
+    public static final int LOCATION_STATUS_ICON_ID
+        = R.drawable.stat_sys_device_access_location_found;
+
+    private static final int[] mHighPowerRequestAppOpArray
+        = new int[] {AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION};
+
+    private Context mContext;
+
+    private AppOpsManager mAppOpsManager;
+    private StatusBarManager mStatusBarManager;
+
+    private boolean mAreActiveLocationRequests;
+
+    private ArrayList<LocationSettingsChangeCallback> mSettingsChangeCallbacks =
+            new ArrayList<LocationSettingsChangeCallback>();
+
+    public LocationControllerImpl(Context context) {
+        mContext = context;
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
+        context.registerReceiver(this, filter);
+
+        mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+        mStatusBarManager
+                = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
+
+        // Register to listen for changes in location settings.
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION);
+        context.registerReceiverAsUser(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                String action = intent.getAction();
+                if (LocationManager.MODE_CHANGED_ACTION.equals(action)) {
+                    locationSettingsChanged();
+                }
+            }
+        }, UserHandle.ALL, intentFilter, null, new Handler());
+
+        // Examine the current location state and initialize the status view.
+        updateActiveLocationRequests();
+        refreshViews();
+    }
+
+    /**
+     * Add a callback to listen for changes in location settings.
+     */
+    public void addSettingsChangedCallback(LocationSettingsChangeCallback cb) {
+        mSettingsChangeCallbacks.add(cb);
+    }
+
+    public void removeSettingsChangedCallback(LocationSettingsChangeCallback cb) {
+        mSettingsChangeCallbacks.remove(cb);
+    }
+
+    /**
+     * Enable or disable location in settings.
+     *
+     * <p>This will attempt to enable/disable every type of location setting
+     * (e.g. high and balanced power).
+     *
+     * <p>If enabling, a user consent dialog will pop up prompting the user to accept.
+     * If the user doesn't accept, network location won't be enabled.
+     *
+     * @return true if attempt to change setting was successful.
+     */
+    public boolean setLocationEnabled(boolean enabled) {
+        int currentUserId = ActivityManager.getCurrentUser();
+        if (isUserLocationRestricted(currentUserId)) {
+            return false;
+        }
+        final ContentResolver cr = mContext.getContentResolver();
+        // When enabling location, a user consent dialog will pop up, and the
+        // setting won't be fully enabled until the user accepts the agreement.
+        int mode = enabled
+                ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY : Settings.Secure.LOCATION_MODE_OFF;
+        // QuickSettings always runs as the owner, so specifically set the settings
+        // for the current foreground user.
+        return Settings.Secure
+                .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId);
+    }
+
+    /**
+     * Returns true if location isn't disabled in settings.
+     */
+    public boolean isLocationEnabled() {
+        ContentResolver resolver = mContext.getContentResolver();
+        // QuickSettings always runs as the owner, so specifically retrieve the settings
+        // for the current foreground user.
+        int mode = Settings.Secure.getIntForUser(resolver, Settings.Secure.LOCATION_MODE,
+                Settings.Secure.LOCATION_MODE_OFF, ActivityManager.getCurrentUser());
+        return mode != Settings.Secure.LOCATION_MODE_OFF;
+    }
+
+    /**
+     * Returns true if the current user is restricted from using location.
+     */
+    private boolean isUserLocationRestricted(int userId) {
+        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        return um.hasUserRestriction(
+                UserManager.DISALLOW_SHARE_LOCATION,
+                new UserHandle(userId));
+    }
+
+    /**
+     * Returns true if there currently exist active high power location requests.
+     */
+    private boolean areActiveHighPowerLocationRequests() {
+        List<AppOpsManager.PackageOps> packages
+            = mAppOpsManager.getPackagesForOps(mHighPowerRequestAppOpArray);
+        // AppOpsManager can return null when there is no requested data.
+        if (packages != null) {
+            final int numPackages = packages.size();
+            for (int packageInd = 0; packageInd < numPackages; packageInd++) {
+                AppOpsManager.PackageOps packageOp = packages.get(packageInd);
+                List<AppOpsManager.OpEntry> opEntries = packageOp.getOps();
+                if (opEntries != null) {
+                    final int numOps = opEntries.size();
+                    for (int opInd = 0; opInd < numOps; opInd++) {
+                        AppOpsManager.OpEntry opEntry = opEntries.get(opInd);
+                        // AppOpsManager should only return OP_MONITOR_HIGH_POWER_LOCATION because
+                        // of the mHighPowerRequestAppOpArray filter, but checking defensively.
+                        if (opEntry.getOp() == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION) {
+                            if (opEntry.isRunning()) {
+                                return true;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    // Updates the status view based on the current state of location requests.
+    private void refreshViews() {
+        if (mAreActiveLocationRequests) {
+            mStatusBarManager.setIcon(LOCATION_STATUS_ICON_PLACEHOLDER, LOCATION_STATUS_ICON_ID, 0,
+                    mContext.getString(R.string.accessibility_location_active));
+        } else {
+            mStatusBarManager.removeIcon(LOCATION_STATUS_ICON_PLACEHOLDER);
+        }
+    }
+
+    // Reads the active location requests and updates the status view if necessary.
+    private void updateActiveLocationRequests() {
+        boolean hadActiveLocationRequests = mAreActiveLocationRequests;
+        mAreActiveLocationRequests = areActiveHighPowerLocationRequests();
+        if (mAreActiveLocationRequests != hadActiveLocationRequests) {
+            refreshViews();
+        }
+    }
+
+    private void locationSettingsChanged() {
+        boolean isEnabled = isLocationEnabled();
+        for (LocationSettingsChangeCallback cb : mSettingsChangeCallbacks) {
+            cb.onLocationSettingsChanged(isEnabled);
+        }
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        final String action = intent.getAction();
+        if (LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) {
+            updateActiveLocationRequests();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 92c008e..dc8f315 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * 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.
@@ -16,153 +16,12 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.net.wimax.WimaxManagerConstants;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
-import android.provider.Settings;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-import android.view.View;
-import android.widget.TextView;
+public interface NetworkController {
 
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.cdma.EriInfo;
-import com.android.internal.util.AsyncChannel;
-import com.android.systemui.DemoMode;
-import com.android.systemui.R;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-public class NetworkController extends BroadcastReceiver implements DemoMode {
-    // debug
-    static final String TAG = "StatusBar.NetworkController";
-    static final boolean DEBUG = false;
-    static final boolean CHATTY = false; // additional diagnostics, but not logspew
-
-    private static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_signal_flightmode;
-
-    // telephony
-    boolean mHspaDataDistinguishable;
-    final TelephonyManager mPhone;
-    boolean mDataConnected;
-    IccCardConstants.State mSimState = IccCardConstants.State.READY;
-    int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
-    int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
-    int mDataState = TelephonyManager.DATA_DISCONNECTED;
-    int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
-    ServiceState mServiceState;
-    SignalStrength mSignalStrength;
-    int[] mDataIconList = TelephonyIcons.DATA_G[0];
-    String mNetworkName;
-    String mNetworkNameDefault;
-    String mNetworkNameSeparator;
-    int mPhoneSignalIconId;
-    int mQSPhoneSignalIconId;
-    int mDataDirectionIconId; // data + data direction on phones
-    int mDataSignalIconId;
-    int mDataTypeIconId;
-    int mQSDataTypeIconId;
-    int mAirplaneIconId;
-    boolean mDataActive;
-    int mLastSignalLevel;
-    boolean mShowPhoneRSSIForData = false;
-    boolean mShowAtLeastThreeGees = false;
-    boolean mAlwaysShowCdmaRssi = false;
-
-    String mContentDescriptionPhoneSignal;
-    String mContentDescriptionWifi;
-    String mContentDescriptionWimax;
-    String mContentDescriptionCombinedSignal;
-    String mContentDescriptionDataType;
-
-    // wifi
-    final WifiManager mWifiManager;
-    AsyncChannel mWifiChannel;
-    boolean mWifiEnabled, mWifiConnected;
-    int mWifiRssi, mWifiLevel;
-    String mWifiSsid;
-    int mWifiIconId = 0;
-    int mQSWifiIconId = 0;
-    int mWifiActivity = WifiManager.DATA_ACTIVITY_NONE;
-
-    // bluetooth
-    private boolean mBluetoothTethered = false;
-    private int mBluetoothTetherIconId =
-        com.android.internal.R.drawable.stat_sys_tether_bluetooth;
-
-    //wimax
-    private boolean mWimaxSupported = false;
-    private boolean mIsWimaxEnabled = false;
-    private boolean mWimaxConnected = false;
-    private boolean mWimaxIdle = false;
-    private int mWimaxIconId = 0;
-    private int mWimaxSignal = 0;
-    private int mWimaxState = 0;
-    private int mWimaxExtraState = 0;
-
-    // data connectivity (regardless of state, can we access the internet?)
-    // state of inet connection - 0 not connected, 100 connected
-    private boolean mConnected = false;
-    private int mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
-    private String mConnectedNetworkTypeName;
-    private int mInetCondition = 0;
-    private int mLastInetCondition = 0;
-    private static final int INET_CONDITION_THRESHOLD = 50;
-
-    private boolean mAirplaneMode = false;
-    private boolean mLastAirplaneMode = true;
-
-    private Locale mLocale = null;
-    private Locale mLastLocale = null;
-
-    // our ui
-    Context mContext;
-    ArrayList<TextView> mCombinedLabelViews = new ArrayList<TextView>();
-    ArrayList<TextView> mMobileLabelViews = new ArrayList<TextView>();
-    ArrayList<TextView> mWifiLabelViews = new ArrayList<TextView>();
-    ArrayList<TextView> mEmergencyLabelViews = new ArrayList<TextView>();
-    ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>();
-    ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks =
-            new ArrayList<NetworkSignalChangedCallback>();
-    int mLastPhoneSignalIconId = -1;
-    int mLastDataDirectionIconId = -1;
-    int mLastWifiIconId = -1;
-    int mLastWimaxIconId = -1;
-    int mLastCombinedSignalIconId = -1;
-    int mLastDataTypeIconId = -1;
-    String mLastCombinedLabel = "";
-
-    private boolean mHasMobileDataFeature;
-
-    boolean mDataAndWifiStacked = false;
-
-    public interface SignalCluster {
-        void setWifiIndicators(boolean visible, int strengthIcon, boolean problem,
-                String contentDescription);
-        void setMobileDataIndicators(boolean visible, int strengthIcon, boolean problem,
-                int typeIcon, String contentDescription, String typeContentDescription);
-        void setIsAirplaneMode(boolean is, int airplaneIcon);
-    }
+    boolean hasMobileDataFeature();
+    void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb);
+    void removeNetworkSignalChangedCallback(NetworkSignalChangedCallback cb);
+    void setWifiEnabled(boolean enabled);
 
     public interface NetworkSignalChangedCallback {
         void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
@@ -174,1304 +33,4 @@
                 String dataTypeContentDescriptionId, String description);
         void onAirplaneModeChanged(boolean enabled);
     }
-
-    /**
-     * Construct this controller object and register for updates.
-     */
-    public NetworkController(Context context) {
-        mContext = context;
-        final Resources res = context.getResources();
-
-        ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
-                Context.CONNECTIVITY_SERVICE);
-        mHasMobileDataFeature = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
-
-        mShowPhoneRSSIForData = res.getBoolean(R.bool.config_showPhoneRSSIForData);
-        mShowAtLeastThreeGees = res.getBoolean(R.bool.config_showMin3G);
-        mAlwaysShowCdmaRssi = res.getBoolean(
-                com.android.internal.R.bool.config_alwaysUseCdmaRssi);
-
-        // set up the default wifi icon, used when no radios have ever appeared
-        updateWifiIcons();
-        updateWimaxIcons();
-
-        // telephony
-        mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
-        mPhone.listen(mPhoneStateListener,
-                          PhoneStateListener.LISTEN_SERVICE_STATE
-                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
-                        | PhoneStateListener.LISTEN_CALL_STATE
-                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
-                        | PhoneStateListener.LISTEN_DATA_ACTIVITY);
-        mHspaDataDistinguishable = mContext.getResources().getBoolean(
-                R.bool.config_hspa_data_distinguishable);
-        mNetworkNameSeparator = mContext.getString(R.string.status_bar_network_name_separator);
-        mNetworkNameDefault = mContext.getString(
-                com.android.internal.R.string.lockscreen_carrier_default);
-        mNetworkName = mNetworkNameDefault;
-
-        // wifi
-        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
-        Handler handler = new WifiHandler();
-        mWifiChannel = new AsyncChannel();
-        Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
-        if (wifiMessenger != null) {
-            mWifiChannel.connect(mContext, handler, wifiMessenger);
-        }
-
-        // broadcasts
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
-        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
-        filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
-        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
-        filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
-        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
-        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        mWimaxSupported = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_wimaxEnabled);
-        if(mWimaxSupported) {
-            filter.addAction(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION);
-            filter.addAction(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION);
-            filter.addAction(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION);
-        }
-        context.registerReceiver(this, filter);
-
-        // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
-        updateAirplaneMode();
-
-        mLastLocale = mContext.getResources().getConfiguration().locale;
-    }
-
-    public boolean hasMobileDataFeature() {
-        return mHasMobileDataFeature;
-    }
-
-    public boolean hasVoiceCallingFeature() {
-        return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
-    }
-
-    public boolean isEmergencyOnly() {
-        return (mServiceState != null && mServiceState.isEmergencyOnly());
-    }
-
-    public void addCombinedLabelView(TextView v) {
-        mCombinedLabelViews.add(v);
-    }
-
-    public void addMobileLabelView(TextView v) {
-        mMobileLabelViews.add(v);
-    }
-
-    public void addWifiLabelView(TextView v) {
-        mWifiLabelViews.add(v);
-    }
-
-    public void addEmergencyLabelView(TextView v) {
-        mEmergencyLabelViews.add(v);
-    }
-
-    public void addSignalCluster(SignalCluster cluster) {
-        mSignalClusters.add(cluster);
-        refreshSignalCluster(cluster);
-    }
-
-    public void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) {
-        mSignalsChangedCallbacks.add(cb);
-        notifySignalsChangedCallbacks(cb);
-    }
-
-    public void refreshSignalCluster(SignalCluster cluster) {
-        if (mDemoMode) return;
-        cluster.setWifiIndicators(
-                // only show wifi in the cluster if connected or if wifi-only
-                mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature),
-                mWifiIconId,
-                mInetCondition == 0,
-                mContentDescriptionWifi);
-
-        if (mIsWimaxEnabled && mWimaxConnected) {
-            // wimax is special
-            cluster.setMobileDataIndicators(
-                    true,
-                    mAlwaysShowCdmaRssi ? mPhoneSignalIconId : mWimaxIconId,
-                    mInetCondition == 0,
-                    mDataTypeIconId,
-                    mContentDescriptionWimax,
-                    mContentDescriptionDataType);
-        } else {
-            // normal mobile data
-            cluster.setMobileDataIndicators(
-                    mHasMobileDataFeature,
-                    mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
-                    mInetCondition == 0,
-                    mDataTypeIconId,
-                    mContentDescriptionPhoneSignal,
-                    mContentDescriptionDataType);
-        }
-        cluster.setIsAirplaneMode(mAirplaneMode, mAirplaneIconId);
-    }
-
-    void notifySignalsChangedCallbacks(NetworkSignalChangedCallback cb) {
-        // only show wifi in the cluster if connected or if wifi-only
-        boolean wifiEnabled = mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature);
-        String wifiDesc = wifiEnabled ?
-                mWifiSsid : null;
-        boolean wifiIn = wifiEnabled && mWifiSsid != null
-                && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
-                || mWifiActivity == WifiManager.DATA_ACTIVITY_IN);
-        boolean wifiOut = wifiEnabled && mWifiSsid != null
-                && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
-                || mWifiActivity == WifiManager.DATA_ACTIVITY_OUT);
-        cb.onWifiSignalChanged(wifiEnabled, mQSWifiIconId, wifiIn, wifiOut,
-                mContentDescriptionWifi, wifiDesc);
-
-        boolean mobileIn = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
-                || mDataActivity == TelephonyManager.DATA_ACTIVITY_IN);
-        boolean mobileOut = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
-                || mDataActivity == TelephonyManager.DATA_ACTIVITY_OUT);
-        if (isEmergencyOnly()) {
-            cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId,
-                    mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
-                    mContentDescriptionDataType, null);
-        } else {
-            if (mIsWimaxEnabled && mWimaxConnected) {
-                // Wimax is special
-                cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId,
-                        mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
-                        mContentDescriptionDataType, mNetworkName);
-            } else {
-                // Normal mobile data
-                cb.onMobileDataSignalChanged(mHasMobileDataFeature, mQSPhoneSignalIconId,
-                        mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
-                        mContentDescriptionDataType, mNetworkName);
-            }
-        }
-        cb.onAirplaneModeChanged(mAirplaneMode);
-    }
-
-    public void setStackedMode(boolean stacked) {
-        mDataAndWifiStacked = true;
-    }
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        final String action = intent.getAction();
-        if (action.equals(WifiManager.RSSI_CHANGED_ACTION)
-                || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)
-                || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-            updateWifiState(intent);
-            refreshViews();
-        } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
-            updateSimState(intent);
-            updateDataIcon();
-            refreshViews();
-        } else if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
-            updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
-                        intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
-                        intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
-                        intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
-            refreshViews();
-        } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
-                 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
-            updateConnectivity(intent);
-            refreshViews();
-        } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
-            refreshLocale();
-            refreshViews();
-        } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
-            refreshLocale();
-            updateAirplaneMode();
-            refreshViews();
-        } else if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION) ||
-                action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION) ||
-                action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
-            updateWimaxState(intent);
-            refreshViews();
-        }
-    }
-
-
-    // ===== Telephony ==============================================================
-
-    PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
-        @Override
-        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
-            if (DEBUG) {
-                Log.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
-                    ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
-            }
-            mSignalStrength = signalStrength;
-            updateTelephonySignalStrength();
-            refreshViews();
-        }
-
-        @Override
-        public void onServiceStateChanged(ServiceState state) {
-            if (DEBUG) {
-                Log.d(TAG, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
-                        + " dataState=" + state.getDataRegState());
-            }
-            mServiceState = state;
-            updateTelephonySignalStrength();
-            updateDataNetType();
-            updateDataIcon();
-            refreshViews();
-        }
-
-        @Override
-        public void onCallStateChanged(int state, String incomingNumber) {
-            if (DEBUG) {
-                Log.d(TAG, "onCallStateChanged state=" + state);
-            }
-            // In cdma, if a voice call is made, RSSI should switch to 1x.
-            if (isCdma()) {
-                updateTelephonySignalStrength();
-                refreshViews();
-            }
-        }
-
-        @Override
-        public void onDataConnectionStateChanged(int state, int networkType) {
-            if (DEBUG) {
-                Log.d(TAG, "onDataConnectionStateChanged: state=" + state
-                        + " type=" + networkType);
-            }
-            mDataState = state;
-            mDataNetType = networkType;
-            updateDataNetType();
-            updateDataIcon();
-            refreshViews();
-        }
-
-        @Override
-        public void onDataActivity(int direction) {
-            if (DEBUG) {
-                Log.d(TAG, "onDataActivity: direction=" + direction);
-            }
-            mDataActivity = direction;
-            updateDataIcon();
-            refreshViews();
-        }
-    };
-
-    private final void updateSimState(Intent intent) {
-        String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
-        if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
-            mSimState = IccCardConstants.State.ABSENT;
-        }
-        else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
-            mSimState = IccCardConstants.State.READY;
-        }
-        else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
-            final String lockedReason =
-                    intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
-            if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
-                mSimState = IccCardConstants.State.PIN_REQUIRED;
-            }
-            else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
-                mSimState = IccCardConstants.State.PUK_REQUIRED;
-            }
-            else {
-                mSimState = IccCardConstants.State.NETWORK_LOCKED;
-            }
-        } else {
-            mSimState = IccCardConstants.State.UNKNOWN;
-        }
-    }
-
-    private boolean isCdma() {
-        return (mSignalStrength != null) && !mSignalStrength.isGsm();
-    }
-
-    private boolean hasService() {
-        if (mServiceState != null) {
-            // Consider the device to be in service if either voice or data service is available.
-            // Some SIM cards are marketed as data-only and do not support voice service, and on
-            // these SIM cards, we want to show signal bars for data service as well as the "no
-            // service" or "emergency calls only" text that indicates that voice is not available.
-            switch(mServiceState.getVoiceRegState()) {
-                case ServiceState.STATE_POWER_OFF:
-                    return false;
-                case ServiceState.STATE_OUT_OF_SERVICE:
-                case ServiceState.STATE_EMERGENCY_ONLY:
-                    return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE;
-                default:
-                    return true;
-            }
-        } else {
-            return false;
-        }
-    }
-
-    private void updateAirplaneMode() {
-        mAirplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
-            Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
-    }
-
-    private void refreshLocale() {
-        mLocale = mContext.getResources().getConfiguration().locale;
-    }
-
-    private final void updateTelephonySignalStrength() {
-        if (!hasService()) {
-            if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: !hasService()");
-            mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
-            mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
-            mDataSignalIconId = R.drawable.stat_sys_signal_null;
-        } else {
-            if (mSignalStrength == null) {
-                if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null");
-                mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
-                mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
-                mDataSignalIconId = R.drawable.stat_sys_signal_null;
-                mContentDescriptionPhoneSignal = mContext.getString(
-                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]);
-            } else {
-                int iconLevel;
-                int[] iconList;
-                if (isCdma() && mAlwaysShowCdmaRssi) {
-                    mLastSignalLevel = iconLevel = mSignalStrength.getCdmaLevel();
-                    if(DEBUG) Log.d(TAG, "mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi
-                            + " set to cdmaLevel=" + mSignalStrength.getCdmaLevel()
-                            + " instead of level=" + mSignalStrength.getLevel());
-                } else {
-                    mLastSignalLevel = iconLevel = mSignalStrength.getLevel();
-                }
-
-                if (isCdma()) {
-                    if (isCdmaEri()) {
-                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
-                    } else {
-                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
-                    }
-                } else {
-                    // Though mPhone is a Manager, this call is not an IPC
-                    if (mPhone.isNetworkRoaming()) {
-                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
-                    } else {
-                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
-                    }
-                }
-                mPhoneSignalIconId = iconList[iconLevel];
-                mQSPhoneSignalIconId =
-                        TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[mInetCondition][iconLevel];
-                mContentDescriptionPhoneSignal = mContext.getString(
-                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]);
-                mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel];
-            }
-        }
-    }
-
-    private final void updateDataNetType() {
-        if (mIsWimaxEnabled && mWimaxConnected) {
-            // wimax is a special 4g network not handled by telephony
-            mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
-            mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
-            mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition];
-            mContentDescriptionDataType = mContext.getString(
-                    R.string.accessibility_data_connection_4g);
-        } else {
-            switch (mDataNetType) {
-                case TelephonyManager.NETWORK_TYPE_UNKNOWN:
-                    if (!mShowAtLeastThreeGees) {
-                        mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
-                        mDataTypeIconId = 0;
-                        mQSDataTypeIconId = 0;
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_gprs);
-                        break;
-                    } else {
-                        // fall through
-                    }
-                case TelephonyManager.NETWORK_TYPE_EDGE:
-                    if (!mShowAtLeastThreeGees) {
-                        mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_e;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_E[mInetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_edge);
-                        break;
-                    } else {
-                        // fall through
-                    }
-                case TelephonyManager.NETWORK_TYPE_UMTS:
-                    mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
-                    mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
-                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
-                    mContentDescriptionDataType = mContext.getString(
-                            R.string.accessibility_data_connection_3g);
-                    break;
-                case TelephonyManager.NETWORK_TYPE_HSDPA:
-                case TelephonyManager.NETWORK_TYPE_HSUPA:
-                case TelephonyManager.NETWORK_TYPE_HSPA:
-                case TelephonyManager.NETWORK_TYPE_HSPAP:
-                    if (mHspaDataDistinguishable) {
-                        mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_h;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_H[mInetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_3_5g);
-                    } else {
-                        mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_3g);
-                    }
-                    break;
-                case TelephonyManager.NETWORK_TYPE_CDMA:
-                    if (!mShowAtLeastThreeGees) {
-                        // display 1xRTT for IS95A/B
-                        mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_cdma);
-                        break;
-                    } else {
-                        // fall through
-                    }
-                case TelephonyManager.NETWORK_TYPE_1xRTT:
-                    if (!mShowAtLeastThreeGees) {
-                        mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_cdma);
-                        break;
-                    } else {
-                        // fall through
-                    }
-                case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
-                case TelephonyManager.NETWORK_TYPE_EVDO_A:
-                case TelephonyManager.NETWORK_TYPE_EVDO_B:
-                case TelephonyManager.NETWORK_TYPE_EHRPD:
-                    mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
-                    mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
-                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
-                    mContentDescriptionDataType = mContext.getString(
-                            R.string.accessibility_data_connection_3g);
-                    break;
-                case TelephonyManager.NETWORK_TYPE_LTE:
-                    boolean show4GforLTE = mContext.getResources().getBoolean(R.bool.config_show4GForLTE);
-                    if (show4GforLTE) {
-                        mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_4g);
-                    } else {
-                        mDataIconList = TelephonyIcons.DATA_LTE[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_lte;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_LTE[mInetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_lte);
-                    }
-                    break;
-                default:
-                    if (!mShowAtLeastThreeGees) {
-                        mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_g;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_G[mInetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_gprs);
-                    } else {
-                        mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_3g);
-                    }
-                    break;
-            }
-        }
-
-        if (isCdma()) {
-            if (isCdmaEri()) {
-                mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
-                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
-            }
-        } else if (mPhone.isNetworkRoaming()) {
-                mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
-                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
-        }
-    }
-
-    boolean isCdmaEri() {
-        if (mServiceState != null) {
-            final int iconIndex = mServiceState.getCdmaEriIconIndex();
-            if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) {
-                final int iconMode = mServiceState.getCdmaEriIconMode();
-                if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
-                        || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    private final void updateDataIcon() {
-        int iconId;
-        boolean visible = true;
-
-        if (!isCdma()) {
-            // GSM case, we have to check also the sim state
-            if (mSimState == IccCardConstants.State.READY ||
-                    mSimState == IccCardConstants.State.UNKNOWN) {
-                if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
-                    switch (mDataActivity) {
-                        case TelephonyManager.DATA_ACTIVITY_IN:
-                            iconId = mDataIconList[1];
-                            break;
-                        case TelephonyManager.DATA_ACTIVITY_OUT:
-                            iconId = mDataIconList[2];
-                            break;
-                        case TelephonyManager.DATA_ACTIVITY_INOUT:
-                            iconId = mDataIconList[3];
-                            break;
-                        default:
-                            iconId = mDataIconList[0];
-                            break;
-                    }
-                    mDataDirectionIconId = iconId;
-                } else {
-                    iconId = 0;
-                    visible = false;
-                }
-            } else {
-                iconId = R.drawable.stat_sys_no_sim;
-                visible = false; // no SIM? no data
-            }
-        } else {
-            // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
-            if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
-                switch (mDataActivity) {
-                    case TelephonyManager.DATA_ACTIVITY_IN:
-                        iconId = mDataIconList[1];
-                        break;
-                    case TelephonyManager.DATA_ACTIVITY_OUT:
-                        iconId = mDataIconList[2];
-                        break;
-                    case TelephonyManager.DATA_ACTIVITY_INOUT:
-                        iconId = mDataIconList[3];
-                        break;
-                    case TelephonyManager.DATA_ACTIVITY_DORMANT:
-                    default:
-                        iconId = mDataIconList[0];
-                        break;
-                }
-            } else {
-                iconId = 0;
-                visible = false;
-            }
-        }
-
-        mDataDirectionIconId = iconId;
-        mDataConnected = visible;
-    }
-
-    void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
-        if (false) {
-            Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
-                    + " showPlmn=" + showPlmn + " plmn=" + plmn);
-        }
-        StringBuilder str = new StringBuilder();
-        boolean something = false;
-        if (showPlmn && plmn != null) {
-            str.append(plmn);
-            something = true;
-        }
-        if (showSpn && spn != null) {
-            if (something) {
-                str.append(mNetworkNameSeparator);
-            }
-            str.append(spn);
-            something = true;
-        }
-        if (something) {
-            mNetworkName = str.toString();
-        } else {
-            mNetworkName = mNetworkNameDefault;
-        }
-    }
-
-    // ===== Wifi ===================================================================
-
-    class WifiHandler extends Handler {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
-                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
-                        mWifiChannel.sendMessage(Message.obtain(this,
-                                AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
-                    } else {
-                        Log.e(TAG, "Failed to connect to wifi");
-                    }
-                    break;
-                case WifiManager.DATA_ACTIVITY_NOTIFICATION:
-                    if (msg.arg1 != mWifiActivity) {
-                        mWifiActivity = msg.arg1;
-                        refreshViews();
-                    }
-                    break;
-                default:
-                    //Ignore
-                    break;
-            }
-        }
-    }
-
-    private void updateWifiState(Intent intent) {
-        final String action = intent.getAction();
-        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
-            mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
-                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
-
-        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-            final NetworkInfo networkInfo = (NetworkInfo)
-                    intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
-            boolean wasConnected = mWifiConnected;
-            mWifiConnected = networkInfo != null && networkInfo.isConnected();
-            // If we just connected, grab the inintial signal strength and ssid
-            if (mWifiConnected && !wasConnected) {
-                // try getting it out of the intent first
-                WifiInfo info = (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
-                if (info == null) {
-                    info = mWifiManager.getConnectionInfo();
-                }
-                if (info != null) {
-                    mWifiSsid = huntForSsid(info);
-                } else {
-                    mWifiSsid = null;
-                }
-            } else if (!mWifiConnected) {
-                mWifiSsid = null;
-            }
-        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
-            mWifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
-            mWifiLevel = WifiManager.calculateSignalLevel(
-                    mWifiRssi, WifiIcons.WIFI_LEVEL_COUNT);
-        }
-
-        updateWifiIcons();
-    }
-
-    private void updateWifiIcons() {
-        if (mWifiConnected) {
-            mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
-            mQSWifiIconId = WifiIcons.QS_WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
-            mContentDescriptionWifi = mContext.getString(
-                    AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[mWifiLevel]);
-        } else {
-            if (mDataAndWifiStacked) {
-                mWifiIconId = 0;
-                mQSWifiIconId = 0;
-            } else {
-                mWifiIconId = mWifiEnabled ? R.drawable.stat_sys_wifi_signal_null : 0;
-                mQSWifiIconId = mWifiEnabled ? R.drawable.ic_qs_wifi_no_network : 0;
-            }
-            mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi);
-        }
-    }
-
-    private String huntForSsid(WifiInfo info) {
-        String ssid = info.getSSID();
-        if (ssid != null) {
-            return ssid;
-        }
-        // OK, it's not in the connectionInfo; we have to go hunting for it
-        List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks();
-        for (WifiConfiguration net : networks) {
-            if (net.networkId == info.getNetworkId()) {
-                return net.SSID;
-            }
-        }
-        return null;
-    }
-
-
-    // ===== Wimax ===================================================================
-    private final void updateWimaxState(Intent intent) {
-        final String action = intent.getAction();
-        boolean wasConnected = mWimaxConnected;
-        if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION)) {
-            int wimaxStatus = intent.getIntExtra(WimaxManagerConstants.EXTRA_4G_STATE,
-                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
-            mIsWimaxEnabled = (wimaxStatus ==
-                    WimaxManagerConstants.NET_4G_STATE_ENABLED);
-        } else if (action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION)) {
-            mWimaxSignal = intent.getIntExtra(WimaxManagerConstants.EXTRA_NEW_SIGNAL_LEVEL, 0);
-        } else if (action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
-            mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE,
-                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
-            mWimaxExtraState = intent.getIntExtra(
-                    WimaxManagerConstants.EXTRA_WIMAX_STATE_DETAIL,
-                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
-            mWimaxConnected = (mWimaxState ==
-                    WimaxManagerConstants.WIMAX_STATE_CONNECTED);
-            mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE);
-        }
-        updateDataNetType();
-        updateWimaxIcons();
-    }
-
-    private void updateWimaxIcons() {
-        if (mIsWimaxEnabled) {
-            if (mWimaxConnected) {
-                if (mWimaxIdle)
-                    mWimaxIconId = WimaxIcons.WIMAX_IDLE;
-                else
-                    mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[mInetCondition][mWimaxSignal];
-                mContentDescriptionWimax = mContext.getString(
-                        AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]);
-            } else {
-                mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED;
-                mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax);
-            }
-        } else {
-            mWimaxIconId = 0;
-        }
-    }
-
-    // ===== Full or limited Internet connectivity ==================================
-
-    private void updateConnectivity(Intent intent) {
-        if (CHATTY) {
-            Log.d(TAG, "updateConnectivity: intent=" + intent);
-        }
-
-        final ConnectivityManager connManager = (ConnectivityManager) mContext
-                .getSystemService(Context.CONNECTIVITY_SERVICE);
-        final NetworkInfo info = connManager.getActiveNetworkInfo();
-
-        // Are we connected at all, by any interface?
-        mConnected = info != null && info.isConnected();
-        if (mConnected) {
-            mConnectedNetworkType = info.getType();
-            mConnectedNetworkTypeName = info.getTypeName();
-        } else {
-            mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
-            mConnectedNetworkTypeName = null;
-        }
-
-        int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
-
-        if (CHATTY) {
-            Log.d(TAG, "updateConnectivity: networkInfo=" + info);
-            Log.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus);
-        }
-
-        mInetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
-
-        if (info != null && info.getType() == ConnectivityManager.TYPE_BLUETOOTH) {
-            mBluetoothTethered = info.isConnected();
-        } else {
-            mBluetoothTethered = false;
-        }
-
-        // We want to update all the icons, all at once, for any condition change
-        updateDataNetType();
-        updateWimaxIcons();
-        updateDataIcon();
-        updateTelephonySignalStrength();
-        updateWifiIcons();
-    }
-
-
-    // ===== Update the views =======================================================
-
-    void refreshViews() {
-        Context context = mContext;
-
-        int combinedSignalIconId = 0;
-        String combinedLabel = "";
-        String wifiLabel = "";
-        String mobileLabel = "";
-        int N;
-        final boolean emergencyOnly = isEmergencyOnly();
-
-        if (!mHasMobileDataFeature) {
-            mDataSignalIconId = mPhoneSignalIconId = 0;
-            mQSPhoneSignalIconId = 0;
-            mobileLabel = "";
-        } else {
-            // We want to show the carrier name if in service and either:
-            //   - We are connected to mobile data, or
-            //   - We are not connected to mobile data, as long as the *reason* packets are not
-            //     being routed over that link is that we have better connectivity via wifi.
-            // If data is disconnected for some other reason but wifi (or ethernet/bluetooth)
-            // is connected, we show nothing.
-            // Otherwise (nothing connected) we show "No internet connection".
-
-            if (mDataConnected) {
-                mobileLabel = mNetworkName;
-            } else if (mConnected || emergencyOnly) {
-                if (hasService() || emergencyOnly) {
-                    // The isEmergencyOnly test covers the case of a phone with no SIM
-                    mobileLabel = mNetworkName;
-                } else {
-                    // Tablets, basically
-                    mobileLabel = "";
-                }
-            } else {
-                mobileLabel
-                    = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
-            }
-
-            // Now for things that should only be shown when actually using mobile data.
-            if (mDataConnected) {
-                combinedSignalIconId = mDataSignalIconId;
-
-                combinedLabel = mobileLabel;
-                combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon()
-                mContentDescriptionCombinedSignal = mContentDescriptionDataType;
-            }
-        }
-
-        if (mWifiConnected) {
-            if (mWifiSsid == null) {
-                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid);
-            } else {
-                wifiLabel = mWifiSsid;
-                if (DEBUG) {
-                    wifiLabel += "xxxxXXXXxxxxXXXX";
-                }
-            }
-
-            combinedLabel = wifiLabel;
-            combinedSignalIconId = mWifiIconId; // set by updateWifiIcons()
-            mContentDescriptionCombinedSignal = mContentDescriptionWifi;
-        } else {
-            if (mHasMobileDataFeature) {
-                wifiLabel = "";
-            } else {
-                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
-            }
-        }
-
-        if (mBluetoothTethered) {
-            combinedLabel = mContext.getString(R.string.bluetooth_tethered);
-            combinedSignalIconId = mBluetoothTetherIconId;
-            mContentDescriptionCombinedSignal = mContext.getString(
-                    R.string.accessibility_bluetooth_tether);
-        }
-
-        final boolean ethernetConnected = (mConnectedNetworkType == ConnectivityManager.TYPE_ETHERNET);
-        if (ethernetConnected) {
-            combinedLabel = context.getString(R.string.ethernet_label);
-        }
-
-        if (mAirplaneMode &&
-                (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) {
-            // Only display the flight-mode icon if not in "emergency calls only" mode.
-
-            // look again; your radios are now airplanes
-            mContentDescriptionPhoneSignal = mContext.getString(
-                    R.string.accessibility_airplane_mode);
-            mAirplaneIconId = FLIGHT_MODE_ICON;
-            mPhoneSignalIconId = mDataSignalIconId = mDataTypeIconId = mQSDataTypeIconId = 0;
-            mQSPhoneSignalIconId = 0;
-
-            // combined values from connected wifi take precedence over airplane mode
-            if (mWifiConnected) {
-                // Suppress "No internet connection." from mobile if wifi connected.
-                mobileLabel = "";
-            } else {
-                if (mHasMobileDataFeature) {
-                    // let the mobile icon show "No internet connection."
-                    wifiLabel = "";
-                } else {
-                    wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
-                    combinedLabel = wifiLabel;
-                }
-                mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal;
-                combinedSignalIconId = mDataSignalIconId;
-            }
-        }
-        else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected && !ethernetConnected) {
-            // pretty much totally disconnected
-
-            combinedLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
-            // On devices without mobile radios, we want to show the wifi icon
-            combinedSignalIconId =
-                mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId;
-            mContentDescriptionCombinedSignal = mHasMobileDataFeature
-                ? mContentDescriptionDataType : mContentDescriptionWifi;
-
-            mDataTypeIconId = 0;
-            mQSDataTypeIconId = 0;
-            if (isCdma()) {
-                if (isCdmaEri()) {
-                    mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
-                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
-                }
-            } else if (mPhone.isNetworkRoaming()) {
-                mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
-                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
-            }
-        }
-
-        if (DEBUG) {
-            Log.d(TAG, "refreshViews connected={"
-                    + (mWifiConnected?" wifi":"")
-                    + (mDataConnected?" data":"")
-                    + " } level="
-                    + ((mSignalStrength == null)?"??":Integer.toString(mSignalStrength.getLevel()))
-                    + " combinedSignalIconId=0x"
-                    + Integer.toHexString(combinedSignalIconId)
-                    + "/" + getResourceName(combinedSignalIconId)
-                    + " mobileLabel=" + mobileLabel
-                    + " wifiLabel=" + wifiLabel
-                    + " emergencyOnly=" + emergencyOnly
-                    + " combinedLabel=" + combinedLabel
-                    + " mAirplaneMode=" + mAirplaneMode
-                    + " mDataActivity=" + mDataActivity
-                    + " mPhoneSignalIconId=0x" + Integer.toHexString(mPhoneSignalIconId)
-                    + " mQSPhoneSignalIconId=0x" + Integer.toHexString(mQSPhoneSignalIconId)
-                    + " mDataDirectionIconId=0x" + Integer.toHexString(mDataDirectionIconId)
-                    + " mDataSignalIconId=0x" + Integer.toHexString(mDataSignalIconId)
-                    + " mDataTypeIconId=0x" + Integer.toHexString(mDataTypeIconId)
-                    + " mQSDataTypeIconId=0x" + Integer.toHexString(mQSDataTypeIconId)
-                    + " mWifiIconId=0x" + Integer.toHexString(mWifiIconId)
-                    + " mQSWifiIconId=0x" + Integer.toHexString(mQSWifiIconId)
-                    + " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId));
-        }
-
-        // update QS
-        for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) {
-            notifySignalsChangedCallbacks(cb);
-        }
-
-        if (mLastPhoneSignalIconId          != mPhoneSignalIconId
-         || mLastWifiIconId                 != mWifiIconId
-         || mLastInetCondition              != mInetCondition
-         || mLastWimaxIconId                != mWimaxIconId
-         || mLastDataTypeIconId             != mDataTypeIconId
-         || mLastAirplaneMode               != mAirplaneMode
-         || mLastLocale                     != mLocale)
-        {
-            // NB: the mLast*s will be updated later
-            for (SignalCluster cluster : mSignalClusters) {
-                refreshSignalCluster(cluster);
-            }
-        }
-
-        if (mLastAirplaneMode != mAirplaneMode) {
-            mLastAirplaneMode = mAirplaneMode;
-        }
-
-        if (mLastLocale != mLocale) {
-            mLastLocale = mLocale;
-        }
-
-        // the phone icon on phones
-        if (mLastPhoneSignalIconId != mPhoneSignalIconId) {
-            mLastPhoneSignalIconId = mPhoneSignalIconId;
-        }
-
-        // the data icon on phones
-        if (mLastDataDirectionIconId != mDataDirectionIconId) {
-            mLastDataDirectionIconId = mDataDirectionIconId;
-        }
-
-        // the wifi icon on phones
-        if (mLastWifiIconId != mWifiIconId) {
-            mLastWifiIconId = mWifiIconId;
-        }
-
-        if (mLastInetCondition != mInetCondition) {
-            mLastInetCondition = mInetCondition;
-        }
-
-        // the wimax icon on phones
-        if (mLastWimaxIconId != mWimaxIconId) {
-            mLastWimaxIconId = mWimaxIconId;
-        }
-        // the combined data signal icon
-        if (mLastCombinedSignalIconId != combinedSignalIconId) {
-            mLastCombinedSignalIconId = combinedSignalIconId;
-        }
-
-        // the data network type overlay
-        if (mLastDataTypeIconId != mDataTypeIconId) {
-            mLastDataTypeIconId = mDataTypeIconId;
-        }
-
-        // the combinedLabel in the notification panel
-        if (!mLastCombinedLabel.equals(combinedLabel)) {
-            mLastCombinedLabel = combinedLabel;
-            N = mCombinedLabelViews.size();
-            for (int i=0; i<N; i++) {
-                TextView v = mCombinedLabelViews.get(i);
-                v.setText(combinedLabel);
-            }
-        }
-
-        // wifi label
-        N = mWifiLabelViews.size();
-        for (int i=0; i<N; i++) {
-            TextView v = mWifiLabelViews.get(i);
-            v.setText(wifiLabel);
-            if ("".equals(wifiLabel)) {
-                v.setVisibility(View.GONE);
-            } else {
-                v.setVisibility(View.VISIBLE);
-            }
-        }
-
-        // mobile label
-        N = mMobileLabelViews.size();
-        for (int i=0; i<N; i++) {
-            TextView v = mMobileLabelViews.get(i);
-            v.setText(mobileLabel);
-            if ("".equals(mobileLabel)) {
-                v.setVisibility(View.GONE);
-            } else {
-                v.setVisibility(View.VISIBLE);
-            }
-        }
-
-        // e-call label
-        N = mEmergencyLabelViews.size();
-        for (int i=0; i<N; i++) {
-            TextView v = mEmergencyLabelViews.get(i);
-            if (!emergencyOnly) {
-                v.setVisibility(View.GONE);
-            } else {
-                v.setText(mobileLabel); // comes from the telephony stack
-                v.setVisibility(View.VISIBLE);
-            }
-        }
-    }
-
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println("NetworkController state:");
-        pw.println(String.format("  %s network type %d (%s)",
-                mConnected?"CONNECTED":"DISCONNECTED",
-                mConnectedNetworkType, mConnectedNetworkTypeName));
-        pw.println("  - telephony ------");
-        pw.print("  hasVoiceCallingFeature()=");
-        pw.println(hasVoiceCallingFeature());
-        pw.print("  hasService()=");
-        pw.println(hasService());
-        pw.print("  mHspaDataDistinguishable=");
-        pw.println(mHspaDataDistinguishable);
-        pw.print("  mDataConnected=");
-        pw.println(mDataConnected);
-        pw.print("  mSimState=");
-        pw.println(mSimState);
-        pw.print("  mPhoneState=");
-        pw.println(mPhoneState);
-        pw.print("  mDataState=");
-        pw.println(mDataState);
-        pw.print("  mDataActivity=");
-        pw.println(mDataActivity);
-        pw.print("  mDataNetType=");
-        pw.print(mDataNetType);
-        pw.print("/");
-        pw.println(TelephonyManager.getNetworkTypeName(mDataNetType));
-        pw.print("  mServiceState=");
-        pw.println(mServiceState);
-        pw.print("  mSignalStrength=");
-        pw.println(mSignalStrength);
-        pw.print("  mLastSignalLevel=");
-        pw.println(mLastSignalLevel);
-        pw.print("  mNetworkName=");
-        pw.println(mNetworkName);
-        pw.print("  mNetworkNameDefault=");
-        pw.println(mNetworkNameDefault);
-        pw.print("  mNetworkNameSeparator=");
-        pw.println(mNetworkNameSeparator.replace("\n","\\n"));
-        pw.print("  mPhoneSignalIconId=0x");
-        pw.print(Integer.toHexString(mPhoneSignalIconId));
-        pw.print("/");
-        pw.print("  mQSPhoneSignalIconId=0x");
-        pw.print(Integer.toHexString(mQSPhoneSignalIconId));
-        pw.print("/");
-        pw.println(getResourceName(mPhoneSignalIconId));
-        pw.print("  mDataDirectionIconId=");
-        pw.print(Integer.toHexString(mDataDirectionIconId));
-        pw.print("/");
-        pw.println(getResourceName(mDataDirectionIconId));
-        pw.print("  mDataSignalIconId=");
-        pw.print(Integer.toHexString(mDataSignalIconId));
-        pw.print("/");
-        pw.println(getResourceName(mDataSignalIconId));
-        pw.print("  mDataTypeIconId=");
-        pw.print(Integer.toHexString(mDataTypeIconId));
-        pw.print("/");
-        pw.println(getResourceName(mDataTypeIconId));
-        pw.print("  mQSDataTypeIconId=");
-        pw.print(Integer.toHexString(mQSDataTypeIconId));
-        pw.print("/");
-        pw.println(getResourceName(mQSDataTypeIconId));
-
-        pw.println("  - wifi ------");
-        pw.print("  mWifiEnabled=");
-        pw.println(mWifiEnabled);
-        pw.print("  mWifiConnected=");
-        pw.println(mWifiConnected);
-        pw.print("  mWifiRssi=");
-        pw.println(mWifiRssi);
-        pw.print("  mWifiLevel=");
-        pw.println(mWifiLevel);
-        pw.print("  mWifiSsid=");
-        pw.println(mWifiSsid);
-        pw.println(String.format("  mWifiIconId=0x%08x/%s",
-                    mWifiIconId, getResourceName(mWifiIconId)));
-        pw.println(String.format("  mQSWifiIconId=0x%08x/%s",
-                    mQSWifiIconId, getResourceName(mQSWifiIconId)));
-        pw.print("  mWifiActivity=");
-        pw.println(mWifiActivity);
-
-        if (mWimaxSupported) {
-            pw.println("  - wimax ------");
-            pw.print("  mIsWimaxEnabled="); pw.println(mIsWimaxEnabled);
-            pw.print("  mWimaxConnected="); pw.println(mWimaxConnected);
-            pw.print("  mWimaxIdle="); pw.println(mWimaxIdle);
-            pw.println(String.format("  mWimaxIconId=0x%08x/%s",
-                        mWimaxIconId, getResourceName(mWimaxIconId)));
-            pw.println(String.format("  mWimaxSignal=%d", mWimaxSignal));
-            pw.println(String.format("  mWimaxState=%d", mWimaxState));
-            pw.println(String.format("  mWimaxExtraState=%d", mWimaxExtraState));
-        }
-
-        pw.println("  - Bluetooth ----");
-        pw.print("  mBtReverseTethered=");
-        pw.println(mBluetoothTethered);
-
-        pw.println("  - connectivity ------");
-        pw.print("  mInetCondition=");
-        pw.println(mInetCondition);
-
-        pw.println("  - icons ------");
-        pw.print("  mLastPhoneSignalIconId=0x");
-        pw.print(Integer.toHexString(mLastPhoneSignalIconId));
-        pw.print("/");
-        pw.println(getResourceName(mLastPhoneSignalIconId));
-        pw.print("  mLastDataDirectionIconId=0x");
-        pw.print(Integer.toHexString(mLastDataDirectionIconId));
-        pw.print("/");
-        pw.println(getResourceName(mLastDataDirectionIconId));
-        pw.print("  mLastWifiIconId=0x");
-        pw.print(Integer.toHexString(mLastWifiIconId));
-        pw.print("/");
-        pw.println(getResourceName(mLastWifiIconId));
-        pw.print("  mLastCombinedSignalIconId=0x");
-        pw.print(Integer.toHexString(mLastCombinedSignalIconId));
-        pw.print("/");
-        pw.println(getResourceName(mLastCombinedSignalIconId));
-        pw.print("  mLastDataTypeIconId=0x");
-        pw.print(Integer.toHexString(mLastDataTypeIconId));
-        pw.print("/");
-        pw.println(getResourceName(mLastDataTypeIconId));
-        pw.print("  mLastCombinedLabel=");
-        pw.print(mLastCombinedLabel);
-        pw.println("");
-    }
-
-    private String getResourceName(int resId) {
-        if (resId != 0) {
-            final Resources res = mContext.getResources();
-            try {
-                return res.getResourceName(resId);
-            } catch (android.content.res.Resources.NotFoundException ex) {
-                return "(unknown)";
-            }
-        } else {
-            return "(null)";
-        }
-    }
-
-    private boolean mDemoMode;
-    private int mDemoInetCondition;
-    private int mDemoWifiLevel;
-    private int mDemoDataTypeIconId;
-    private int mDemoMobileLevel;
-
-    @Override
-    public void dispatchDemoCommand(String command, Bundle args) {
-        if (!mDemoMode && command.equals(COMMAND_ENTER)) {
-            mDemoMode = true;
-            mDemoWifiLevel = mWifiLevel;
-            mDemoInetCondition = mInetCondition;
-            mDemoDataTypeIconId = mDataTypeIconId;
-            mDemoMobileLevel = mLastSignalLevel;
-        } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
-            mDemoMode = false;
-            for (SignalCluster cluster : mSignalClusters) {
-                refreshSignalCluster(cluster);
-            }
-        } else if (mDemoMode && command.equals(COMMAND_NETWORK)) {
-            String airplane = args.getString("airplane");
-            if (airplane != null) {
-                boolean show = airplane.equals("show");
-                for (SignalCluster cluster : mSignalClusters) {
-                    cluster.setIsAirplaneMode(show, FLIGHT_MODE_ICON);
-                }
-            }
-            String fully = args.getString("fully");
-            if (fully != null) {
-                mDemoInetCondition = Boolean.parseBoolean(fully) ? 1 : 0;
-            }
-            String wifi = args.getString("wifi");
-            if (wifi != null) {
-                boolean show = wifi.equals("show");
-                String level = args.getString("level");
-                if (level != null) {
-                    mDemoWifiLevel = level.equals("null") ? -1
-                            : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
-                }
-                int iconId = mDemoWifiLevel < 0 ? R.drawable.stat_sys_wifi_signal_null
-                        : WifiIcons.WIFI_SIGNAL_STRENGTH[mDemoInetCondition][mDemoWifiLevel];
-                for (SignalCluster cluster : mSignalClusters) {
-                    cluster.setWifiIndicators(
-                            show,
-                            iconId,
-                            mDemoInetCondition == 0,
-                            "Demo");
-                }
-            }
-            String mobile = args.getString("mobile");
-            if (mobile != null) {
-                boolean show = mobile.equals("show");
-                String datatype = args.getString("datatype");
-                if (datatype != null) {
-                    mDemoDataTypeIconId =
-                            datatype.equals("1x") ? R.drawable.stat_sys_data_fully_connected_1x :
-                            datatype.equals("3g") ? R.drawable.stat_sys_data_fully_connected_3g :
-                            datatype.equals("4g") ? R.drawable.stat_sys_data_fully_connected_4g :
-                            datatype.equals("e") ? R.drawable.stat_sys_data_fully_connected_e :
-                            datatype.equals("g") ? R.drawable.stat_sys_data_fully_connected_g :
-                            datatype.equals("h") ? R.drawable.stat_sys_data_fully_connected_h :
-                            datatype.equals("lte") ? R.drawable.stat_sys_data_fully_connected_lte :
-                            datatype.equals("roam")
-                                    ? R.drawable.stat_sys_data_fully_connected_roam :
-                            0;
-                }
-                int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
-                String level = args.getString("level");
-                if (level != null) {
-                    mDemoMobileLevel = level.equals("null") ? -1
-                            : Math.min(Integer.parseInt(level), icons[0].length - 1);
-                }
-                int iconId = mDemoMobileLevel < 0 ? R.drawable.stat_sys_signal_null :
-                        icons[mDemoInetCondition][mDemoMobileLevel];
-                for (SignalCluster cluster : mSignalClusters) {
-                    cluster.setMobileDataIndicators(
-                            show,
-                            iconId,
-                            mDemoInetCondition == 0,
-                            mDemoDataTypeIconId,
-                            "Demo",
-                            "Demo");
-                }
-            }
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
new file mode 100644
index 0000000..966c0b0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -0,0 +1,1491 @@
+/*
+ * Copyright (C) 2010 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.statusbar.policy;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.net.wimax.WimaxManagerConstants;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.provider.Settings;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.cdma.EriInfo;
+import com.android.internal.util.AsyncChannel;
+import com.android.systemui.DemoMode;
+import com.android.systemui.R;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+/** Platform implementation of the network controller. **/
+public class NetworkControllerImpl extends BroadcastReceiver
+        implements NetworkController, DemoMode {
+    // debug
+    static final String TAG = "StatusBar.NetworkController";
+    static final boolean DEBUG = false;
+    static final boolean CHATTY = false; // additional diagnostics, but not logspew
+
+    private static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_signal_flightmode;
+
+    // telephony
+    boolean mHspaDataDistinguishable;
+    final TelephonyManager mPhone;
+    boolean mDataConnected;
+    IccCardConstants.State mSimState = IccCardConstants.State.READY;
+    int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
+    int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+    int mDataState = TelephonyManager.DATA_DISCONNECTED;
+    int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
+    ServiceState mServiceState;
+    SignalStrength mSignalStrength;
+    int[] mDataIconList = TelephonyIcons.DATA_G[0];
+    String mNetworkName;
+    String mNetworkNameDefault;
+    String mNetworkNameSeparator;
+    int mPhoneSignalIconId;
+    int mQSPhoneSignalIconId;
+    int mDataDirectionIconId; // data + data direction on phones
+    int mDataSignalIconId;
+    int mDataTypeIconId;
+    int mQSDataTypeIconId;
+    int mAirplaneIconId;
+    boolean mDataActive;
+    int mLastSignalLevel;
+    boolean mShowPhoneRSSIForData = false;
+    boolean mShowAtLeastThreeGees = false;
+    boolean mAlwaysShowCdmaRssi = false;
+
+    String mContentDescriptionPhoneSignal;
+    String mContentDescriptionWifi;
+    String mContentDescriptionWimax;
+    String mContentDescriptionCombinedSignal;
+    String mContentDescriptionDataType;
+
+    // wifi
+    final WifiManager mWifiManager;
+    AsyncChannel mWifiChannel;
+    boolean mWifiEnabled, mWifiConnected;
+    int mWifiRssi, mWifiLevel;
+    String mWifiSsid;
+    int mWifiIconId = 0;
+    int mQSWifiIconId = 0;
+    int mWifiActivity = WifiManager.DATA_ACTIVITY_NONE;
+
+    // bluetooth
+    private boolean mBluetoothTethered = false;
+    private int mBluetoothTetherIconId =
+        com.android.internal.R.drawable.stat_sys_tether_bluetooth;
+
+    //wimax
+    private boolean mWimaxSupported = false;
+    private boolean mIsWimaxEnabled = false;
+    private boolean mWimaxConnected = false;
+    private boolean mWimaxIdle = false;
+    private int mWimaxIconId = 0;
+    private int mWimaxSignal = 0;
+    private int mWimaxState = 0;
+    private int mWimaxExtraState = 0;
+
+    // data connectivity (regardless of state, can we access the internet?)
+    // state of inet connection - 0 not connected, 100 connected
+    private boolean mConnected = false;
+    private int mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
+    private String mConnectedNetworkTypeName;
+    private int mInetCondition = 0;
+    private int mLastInetCondition = 0;
+    private static final int INET_CONDITION_THRESHOLD = 50;
+
+    private boolean mAirplaneMode = false;
+    private boolean mLastAirplaneMode = true;
+
+    private Locale mLocale = null;
+    private Locale mLastLocale = null;
+
+    // our ui
+    Context mContext;
+    ArrayList<TextView> mCombinedLabelViews = new ArrayList<TextView>();
+    ArrayList<TextView> mMobileLabelViews = new ArrayList<TextView>();
+    ArrayList<TextView> mWifiLabelViews = new ArrayList<TextView>();
+    ArrayList<TextView> mEmergencyLabelViews = new ArrayList<TextView>();
+    ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>();
+    ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks =
+            new ArrayList<NetworkSignalChangedCallback>();
+    int mLastPhoneSignalIconId = -1;
+    int mLastDataDirectionIconId = -1;
+    int mLastWifiIconId = -1;
+    int mLastWimaxIconId = -1;
+    int mLastCombinedSignalIconId = -1;
+    int mLastDataTypeIconId = -1;
+    String mLastCombinedLabel = "";
+
+    private boolean mHasMobileDataFeature;
+
+    boolean mDataAndWifiStacked = false;
+
+    public interface SignalCluster {
+        void setWifiIndicators(boolean visible, int strengthIcon, boolean problem,
+                String contentDescription);
+        void setMobileDataIndicators(boolean visible, int strengthIcon, boolean problem,
+                int typeIcon, String contentDescription, String typeContentDescription);
+        void setIsAirplaneMode(boolean is, int airplaneIcon);
+    }
+
+    /**
+     * Construct this controller object and register for updates.
+     */
+    public NetworkControllerImpl(Context context) {
+        mContext = context;
+        final Resources res = context.getResources();
+
+        ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
+                Context.CONNECTIVITY_SERVICE);
+        mHasMobileDataFeature = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+
+        mShowPhoneRSSIForData = res.getBoolean(R.bool.config_showPhoneRSSIForData);
+        mShowAtLeastThreeGees = res.getBoolean(R.bool.config_showMin3G);
+        mAlwaysShowCdmaRssi = res.getBoolean(
+                com.android.internal.R.bool.config_alwaysUseCdmaRssi);
+
+        // set up the default wifi icon, used when no radios have ever appeared
+        updateWifiIcons();
+        updateWimaxIcons();
+
+        // telephony
+        mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
+        mPhone.listen(mPhoneStateListener,
+                          PhoneStateListener.LISTEN_SERVICE_STATE
+                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
+                        | PhoneStateListener.LISTEN_CALL_STATE
+                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
+                        | PhoneStateListener.LISTEN_DATA_ACTIVITY);
+        mHspaDataDistinguishable = mContext.getResources().getBoolean(
+                R.bool.config_hspa_data_distinguishable);
+        mNetworkNameSeparator = mContext.getString(R.string.status_bar_network_name_separator);
+        mNetworkNameDefault = mContext.getString(
+                com.android.internal.R.string.lockscreen_carrier_default);
+        mNetworkName = mNetworkNameDefault;
+
+        // wifi
+        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        Handler handler = new WifiHandler();
+        mWifiChannel = new AsyncChannel();
+        Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
+        if (wifiMessenger != null) {
+            mWifiChannel.connect(mContext, handler, wifiMessenger);
+        }
+
+        // broadcasts
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
+        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
+        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+        filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
+        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        mWimaxSupported = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_wimaxEnabled);
+        if(mWimaxSupported) {
+            filter.addAction(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION);
+            filter.addAction(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION);
+            filter.addAction(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION);
+        }
+        context.registerReceiver(this, filter);
+
+        // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
+        updateAirplaneMode();
+
+        mLastLocale = mContext.getResources().getConfiguration().locale;
+    }
+
+    public boolean hasMobileDataFeature() {
+        return mHasMobileDataFeature;
+    }
+
+    public boolean hasVoiceCallingFeature() {
+        return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
+    }
+
+    public boolean isEmergencyOnly() {
+        return (mServiceState != null && mServiceState.isEmergencyOnly());
+    }
+
+    public void addCombinedLabelView(TextView v) {
+        mCombinedLabelViews.add(v);
+    }
+
+    public void addMobileLabelView(TextView v) {
+        mMobileLabelViews.add(v);
+    }
+
+    public void addWifiLabelView(TextView v) {
+        mWifiLabelViews.add(v);
+    }
+
+    public void addEmergencyLabelView(TextView v) {
+        mEmergencyLabelViews.add(v);
+    }
+
+    public void addSignalCluster(SignalCluster cluster) {
+        mSignalClusters.add(cluster);
+        refreshSignalCluster(cluster);
+    }
+
+    public void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) {
+        mSignalsChangedCallbacks.add(cb);
+        notifySignalsChangedCallbacks(cb);
+    }
+
+    public void removeNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) {
+        mSignalsChangedCallbacks.remove(cb);
+    }
+
+    @Override
+    public void setWifiEnabled(final boolean enabled) {
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... args) {
+                // Disable tethering if enabling Wifi
+                final int wifiApState = mWifiManager.getWifiApState();
+                if (enabled && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
+                               (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
+                    mWifiManager.setWifiApEnabled(null, false);
+                }
+
+                mWifiManager.setWifiEnabled(enabled);
+                return null;
+            }
+        }.execute();
+    }
+
+    public void refreshSignalCluster(SignalCluster cluster) {
+        if (mDemoMode) return;
+        cluster.setWifiIndicators(
+                // only show wifi in the cluster if connected or if wifi-only
+                mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature),
+                mWifiIconId,
+                mInetCondition == 0,
+                mContentDescriptionWifi);
+
+        if (mIsWimaxEnabled && mWimaxConnected) {
+            // wimax is special
+            cluster.setMobileDataIndicators(
+                    true,
+                    mAlwaysShowCdmaRssi ? mPhoneSignalIconId : mWimaxIconId,
+                    mInetCondition == 0,
+                    mDataTypeIconId,
+                    mContentDescriptionWimax,
+                    mContentDescriptionDataType);
+        } else {
+            // normal mobile data
+            cluster.setMobileDataIndicators(
+                    mHasMobileDataFeature,
+                    mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
+                    mInetCondition == 0,
+                    mDataTypeIconId,
+                    mContentDescriptionPhoneSignal,
+                    mContentDescriptionDataType);
+        }
+        cluster.setIsAirplaneMode(mAirplaneMode, mAirplaneIconId);
+    }
+
+    void notifySignalsChangedCallbacks(NetworkSignalChangedCallback cb) {
+        // only show wifi in the cluster if connected or if wifi-only
+        boolean wifiEnabled = mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature);
+        String wifiDesc = wifiEnabled ?
+                mWifiSsid : null;
+        boolean wifiIn = wifiEnabled && mWifiSsid != null
+                && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
+                || mWifiActivity == WifiManager.DATA_ACTIVITY_IN);
+        boolean wifiOut = wifiEnabled && mWifiSsid != null
+                && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
+                || mWifiActivity == WifiManager.DATA_ACTIVITY_OUT);
+        cb.onWifiSignalChanged(wifiEnabled, mQSWifiIconId, wifiIn, wifiOut,
+                mContentDescriptionWifi, wifiDesc);
+
+        boolean mobileIn = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
+                || mDataActivity == TelephonyManager.DATA_ACTIVITY_IN);
+        boolean mobileOut = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
+                || mDataActivity == TelephonyManager.DATA_ACTIVITY_OUT);
+        if (isEmergencyOnly()) {
+            cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId,
+                    mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
+                    mContentDescriptionDataType, null);
+        } else {
+            if (mIsWimaxEnabled && mWimaxConnected) {
+                // Wimax is special
+                cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId,
+                        mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
+                        mContentDescriptionDataType, mNetworkName);
+            } else {
+                // Normal mobile data
+                cb.onMobileDataSignalChanged(mHasMobileDataFeature, mQSPhoneSignalIconId,
+                        mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
+                        mContentDescriptionDataType, mNetworkName);
+            }
+        }
+        cb.onAirplaneModeChanged(mAirplaneMode);
+    }
+
+    public void setStackedMode(boolean stacked) {
+        mDataAndWifiStacked = true;
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        final String action = intent.getAction();
+        if (action.equals(WifiManager.RSSI_CHANGED_ACTION)
+                || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)
+                || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+            updateWifiState(intent);
+            refreshViews();
+        } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
+            updateSimState(intent);
+            updateDataIcon();
+            refreshViews();
+        } else if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
+            updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
+                        intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
+                        intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
+                        intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
+            refreshViews();
+        } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
+                 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
+            updateConnectivity(intent);
+            refreshViews();
+        } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
+            refreshLocale();
+            refreshViews();
+        } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
+            refreshLocale();
+            updateAirplaneMode();
+            refreshViews();
+        } else if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION) ||
+                action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION) ||
+                action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
+            updateWimaxState(intent);
+            refreshViews();
+        }
+    }
+
+
+    // ===== Telephony ==============================================================
+
+    PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+        @Override
+        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+            if (DEBUG) {
+                Log.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
+                    ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
+            }
+            mSignalStrength = signalStrength;
+            updateTelephonySignalStrength();
+            refreshViews();
+        }
+
+        @Override
+        public void onServiceStateChanged(ServiceState state) {
+            if (DEBUG) {
+                Log.d(TAG, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
+                        + " dataState=" + state.getDataRegState());
+            }
+            mServiceState = state;
+            updateTelephonySignalStrength();
+            updateDataNetType();
+            updateDataIcon();
+            refreshViews();
+        }
+
+        @Override
+        public void onCallStateChanged(int state, String incomingNumber) {
+            if (DEBUG) {
+                Log.d(TAG, "onCallStateChanged state=" + state);
+            }
+            // In cdma, if a voice call is made, RSSI should switch to 1x.
+            if (isCdma()) {
+                updateTelephonySignalStrength();
+                refreshViews();
+            }
+        }
+
+        @Override
+        public void onDataConnectionStateChanged(int state, int networkType) {
+            if (DEBUG) {
+                Log.d(TAG, "onDataConnectionStateChanged: state=" + state
+                        + " type=" + networkType);
+            }
+            mDataState = state;
+            mDataNetType = networkType;
+            updateDataNetType();
+            updateDataIcon();
+            refreshViews();
+        }
+
+        @Override
+        public void onDataActivity(int direction) {
+            if (DEBUG) {
+                Log.d(TAG, "onDataActivity: direction=" + direction);
+            }
+            mDataActivity = direction;
+            updateDataIcon();
+            refreshViews();
+        }
+    };
+
+    private final void updateSimState(Intent intent) {
+        String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
+        if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
+            mSimState = IccCardConstants.State.ABSENT;
+        }
+        else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
+            mSimState = IccCardConstants.State.READY;
+        }
+        else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
+            final String lockedReason =
+                    intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
+            if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
+                mSimState = IccCardConstants.State.PIN_REQUIRED;
+            }
+            else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
+                mSimState = IccCardConstants.State.PUK_REQUIRED;
+            }
+            else {
+                mSimState = IccCardConstants.State.NETWORK_LOCKED;
+            }
+        } else {
+            mSimState = IccCardConstants.State.UNKNOWN;
+        }
+    }
+
+    private boolean isCdma() {
+        return (mSignalStrength != null) && !mSignalStrength.isGsm();
+    }
+
+    private boolean hasService() {
+        if (mServiceState != null) {
+            // Consider the device to be in service if either voice or data service is available.
+            // Some SIM cards are marketed as data-only and do not support voice service, and on
+            // these SIM cards, we want to show signal bars for data service as well as the "no
+            // service" or "emergency calls only" text that indicates that voice is not available.
+            switch(mServiceState.getVoiceRegState()) {
+                case ServiceState.STATE_POWER_OFF:
+                    return false;
+                case ServiceState.STATE_OUT_OF_SERVICE:
+                case ServiceState.STATE_EMERGENCY_ONLY:
+                    return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE;
+                default:
+                    return true;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    private void updateAirplaneMode() {
+        mAirplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
+            Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
+    }
+
+    private void refreshLocale() {
+        mLocale = mContext.getResources().getConfiguration().locale;
+    }
+
+    private final void updateTelephonySignalStrength() {
+        if (!hasService()) {
+            if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: !hasService()");
+            mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
+            mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
+            mDataSignalIconId = R.drawable.stat_sys_signal_null;
+        } else {
+            if (mSignalStrength == null) {
+                if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null");
+                mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
+                mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
+                mDataSignalIconId = R.drawable.stat_sys_signal_null;
+                mContentDescriptionPhoneSignal = mContext.getString(
+                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]);
+            } else {
+                int iconLevel;
+                int[] iconList;
+                if (isCdma() && mAlwaysShowCdmaRssi) {
+                    mLastSignalLevel = iconLevel = mSignalStrength.getCdmaLevel();
+                    if(DEBUG) Log.d(TAG, "mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi
+                            + " set to cdmaLevel=" + mSignalStrength.getCdmaLevel()
+                            + " instead of level=" + mSignalStrength.getLevel());
+                } else {
+                    mLastSignalLevel = iconLevel = mSignalStrength.getLevel();
+                }
+
+                if (isCdma()) {
+                    if (isCdmaEri()) {
+                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
+                    } else {
+                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
+                    }
+                } else {
+                    // Though mPhone is a Manager, this call is not an IPC
+                    if (mPhone.isNetworkRoaming()) {
+                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
+                    } else {
+                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
+                    }
+                }
+                mPhoneSignalIconId = iconList[iconLevel];
+                mQSPhoneSignalIconId =
+                        TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[mInetCondition][iconLevel];
+                mContentDescriptionPhoneSignal = mContext.getString(
+                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]);
+                mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel];
+            }
+        }
+    }
+
+    private final void updateDataNetType() {
+        if (mIsWimaxEnabled && mWimaxConnected) {
+            // wimax is a special 4g network not handled by telephony
+            mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
+            mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
+            mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition];
+            mContentDescriptionDataType = mContext.getString(
+                    R.string.accessibility_data_connection_4g);
+        } else {
+            switch (mDataNetType) {
+                case TelephonyManager.NETWORK_TYPE_UNKNOWN:
+                    if (!mShowAtLeastThreeGees) {
+                        mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
+                        mDataTypeIconId = 0;
+                        mQSDataTypeIconId = 0;
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_gprs);
+                        break;
+                    } else {
+                        // fall through
+                    }
+                case TelephonyManager.NETWORK_TYPE_EDGE:
+                    if (!mShowAtLeastThreeGees) {
+                        mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_e;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_E[mInetCondition];
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_edge);
+                        break;
+                    } else {
+                        // fall through
+                    }
+                case TelephonyManager.NETWORK_TYPE_UMTS:
+                    mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+                    mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
+                    mContentDescriptionDataType = mContext.getString(
+                            R.string.accessibility_data_connection_3g);
+                    break;
+                case TelephonyManager.NETWORK_TYPE_HSDPA:
+                case TelephonyManager.NETWORK_TYPE_HSUPA:
+                case TelephonyManager.NETWORK_TYPE_HSPA:
+                case TelephonyManager.NETWORK_TYPE_HSPAP:
+                    if (mHspaDataDistinguishable) {
+                        mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_h;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_H[mInetCondition];
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_3_5g);
+                    } else {
+                        mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_3g);
+                    }
+                    break;
+                case TelephonyManager.NETWORK_TYPE_CDMA:
+                    if (!mShowAtLeastThreeGees) {
+                        // display 1xRTT for IS95A/B
+                        mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition];
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_cdma);
+                        break;
+                    } else {
+                        // fall through
+                    }
+                case TelephonyManager.NETWORK_TYPE_1xRTT:
+                    if (!mShowAtLeastThreeGees) {
+                        mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition];
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_cdma);
+                        break;
+                    } else {
+                        // fall through
+                    }
+                case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
+                case TelephonyManager.NETWORK_TYPE_EVDO_A:
+                case TelephonyManager.NETWORK_TYPE_EVDO_B:
+                case TelephonyManager.NETWORK_TYPE_EHRPD:
+                    mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+                    mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
+                    mContentDescriptionDataType = mContext.getString(
+                            R.string.accessibility_data_connection_3g);
+                    break;
+                case TelephonyManager.NETWORK_TYPE_LTE:
+                    boolean show4GforLTE = mContext.getResources().getBoolean(R.bool.config_show4GForLTE);
+                    if (show4GforLTE) {
+                        mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition];
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_4g);
+                    } else {
+                        mDataIconList = TelephonyIcons.DATA_LTE[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_lte;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_LTE[mInetCondition];
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_lte);
+                    }
+                    break;
+                default:
+                    if (!mShowAtLeastThreeGees) {
+                        mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_g;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_G[mInetCondition];
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_gprs);
+                    } else {
+                        mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_3g);
+                    }
+                    break;
+            }
+        }
+
+        if (isCdma()) {
+            if (isCdmaEri()) {
+                mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
+            }
+        } else if (mPhone.isNetworkRoaming()) {
+                mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
+        }
+    }
+
+    boolean isCdmaEri() {
+        if (mServiceState != null) {
+            final int iconIndex = mServiceState.getCdmaEriIconIndex();
+            if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) {
+                final int iconMode = mServiceState.getCdmaEriIconMode();
+                if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
+                        || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private final void updateDataIcon() {
+        int iconId;
+        boolean visible = true;
+
+        if (!isCdma()) {
+            // GSM case, we have to check also the sim state
+            if (mSimState == IccCardConstants.State.READY ||
+                    mSimState == IccCardConstants.State.UNKNOWN) {
+                if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
+                    switch (mDataActivity) {
+                        case TelephonyManager.DATA_ACTIVITY_IN:
+                            iconId = mDataIconList[1];
+                            break;
+                        case TelephonyManager.DATA_ACTIVITY_OUT:
+                            iconId = mDataIconList[2];
+                            break;
+                        case TelephonyManager.DATA_ACTIVITY_INOUT:
+                            iconId = mDataIconList[3];
+                            break;
+                        default:
+                            iconId = mDataIconList[0];
+                            break;
+                    }
+                    mDataDirectionIconId = iconId;
+                } else {
+                    iconId = 0;
+                    visible = false;
+                }
+            } else {
+                iconId = R.drawable.stat_sys_no_sim;
+                visible = false; // no SIM? no data
+            }
+        } else {
+            // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
+            if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
+                switch (mDataActivity) {
+                    case TelephonyManager.DATA_ACTIVITY_IN:
+                        iconId = mDataIconList[1];
+                        break;
+                    case TelephonyManager.DATA_ACTIVITY_OUT:
+                        iconId = mDataIconList[2];
+                        break;
+                    case TelephonyManager.DATA_ACTIVITY_INOUT:
+                        iconId = mDataIconList[3];
+                        break;
+                    case TelephonyManager.DATA_ACTIVITY_DORMANT:
+                    default:
+                        iconId = mDataIconList[0];
+                        break;
+                }
+            } else {
+                iconId = 0;
+                visible = false;
+            }
+        }
+
+        mDataDirectionIconId = iconId;
+        mDataConnected = visible;
+    }
+
+    void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
+        if (false) {
+            Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
+                    + " showPlmn=" + showPlmn + " plmn=" + plmn);
+        }
+        StringBuilder str = new StringBuilder();
+        boolean something = false;
+        if (showPlmn && plmn != null) {
+            str.append(plmn);
+            something = true;
+        }
+        if (showSpn && spn != null) {
+            if (something) {
+                str.append(mNetworkNameSeparator);
+            }
+            str.append(spn);
+            something = true;
+        }
+        if (something) {
+            mNetworkName = str.toString();
+        } else {
+            mNetworkName = mNetworkNameDefault;
+        }
+    }
+
+    // ===== Wifi ===================================================================
+
+    class WifiHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
+                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+                        mWifiChannel.sendMessage(Message.obtain(this,
+                                AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
+                    } else {
+                        Log.e(TAG, "Failed to connect to wifi");
+                    }
+                    break;
+                case WifiManager.DATA_ACTIVITY_NOTIFICATION:
+                    if (msg.arg1 != mWifiActivity) {
+                        mWifiActivity = msg.arg1;
+                        refreshViews();
+                    }
+                    break;
+                default:
+                    //Ignore
+                    break;
+            }
+        }
+    }
+
+    private void updateWifiState(Intent intent) {
+        final String action = intent.getAction();
+        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+            mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
+
+        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+            final NetworkInfo networkInfo = (NetworkInfo)
+                    intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
+            boolean wasConnected = mWifiConnected;
+            mWifiConnected = networkInfo != null && networkInfo.isConnected();
+            // If we just connected, grab the inintial signal strength and ssid
+            if (mWifiConnected && !wasConnected) {
+                // try getting it out of the intent first
+                WifiInfo info = (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
+                if (info == null) {
+                    info = mWifiManager.getConnectionInfo();
+                }
+                if (info != null) {
+                    mWifiSsid = huntForSsid(info);
+                } else {
+                    mWifiSsid = null;
+                }
+            } else if (!mWifiConnected) {
+                mWifiSsid = null;
+            }
+        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
+            mWifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
+            mWifiLevel = WifiManager.calculateSignalLevel(
+                    mWifiRssi, WifiIcons.WIFI_LEVEL_COUNT);
+        }
+
+        updateWifiIcons();
+    }
+
+    private void updateWifiIcons() {
+        if (mWifiConnected) {
+            mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
+            mQSWifiIconId = WifiIcons.QS_WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
+            mContentDescriptionWifi = mContext.getString(
+                    AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[mWifiLevel]);
+        } else {
+            if (mDataAndWifiStacked) {
+                mWifiIconId = 0;
+                mQSWifiIconId = 0;
+            } else {
+                mWifiIconId = mWifiEnabled ? R.drawable.stat_sys_wifi_signal_null : 0;
+                mQSWifiIconId = mWifiEnabled ? R.drawable.ic_qs_wifi_no_network : 0;
+            }
+            mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi);
+        }
+    }
+
+    private String huntForSsid(WifiInfo info) {
+        String ssid = info.getSSID();
+        if (ssid != null) {
+            return ssid;
+        }
+        // OK, it's not in the connectionInfo; we have to go hunting for it
+        List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks();
+        for (WifiConfiguration net : networks) {
+            if (net.networkId == info.getNetworkId()) {
+                return net.SSID;
+            }
+        }
+        return null;
+    }
+
+
+    // ===== Wimax ===================================================================
+    private final void updateWimaxState(Intent intent) {
+        final String action = intent.getAction();
+        boolean wasConnected = mWimaxConnected;
+        if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION)) {
+            int wimaxStatus = intent.getIntExtra(WimaxManagerConstants.EXTRA_4G_STATE,
+                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
+            mIsWimaxEnabled = (wimaxStatus ==
+                    WimaxManagerConstants.NET_4G_STATE_ENABLED);
+        } else if (action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION)) {
+            mWimaxSignal = intent.getIntExtra(WimaxManagerConstants.EXTRA_NEW_SIGNAL_LEVEL, 0);
+        } else if (action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
+            mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE,
+                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
+            mWimaxExtraState = intent.getIntExtra(
+                    WimaxManagerConstants.EXTRA_WIMAX_STATE_DETAIL,
+                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
+            mWimaxConnected = (mWimaxState ==
+                    WimaxManagerConstants.WIMAX_STATE_CONNECTED);
+            mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE);
+        }
+        updateDataNetType();
+        updateWimaxIcons();
+    }
+
+    private void updateWimaxIcons() {
+        if (mIsWimaxEnabled) {
+            if (mWimaxConnected) {
+                if (mWimaxIdle)
+                    mWimaxIconId = WimaxIcons.WIMAX_IDLE;
+                else
+                    mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[mInetCondition][mWimaxSignal];
+                mContentDescriptionWimax = mContext.getString(
+                        AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]);
+            } else {
+                mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED;
+                mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax);
+            }
+        } else {
+            mWimaxIconId = 0;
+        }
+    }
+
+    // ===== Full or limited Internet connectivity ==================================
+
+    private void updateConnectivity(Intent intent) {
+        if (CHATTY) {
+            Log.d(TAG, "updateConnectivity: intent=" + intent);
+        }
+
+        final ConnectivityManager connManager = (ConnectivityManager) mContext
+                .getSystemService(Context.CONNECTIVITY_SERVICE);
+        final NetworkInfo info = connManager.getActiveNetworkInfo();
+
+        // Are we connected at all, by any interface?
+        mConnected = info != null && info.isConnected();
+        if (mConnected) {
+            mConnectedNetworkType = info.getType();
+            mConnectedNetworkTypeName = info.getTypeName();
+        } else {
+            mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
+            mConnectedNetworkTypeName = null;
+        }
+
+        int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
+
+        if (CHATTY) {
+            Log.d(TAG, "updateConnectivity: networkInfo=" + info);
+            Log.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus);
+        }
+
+        mInetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
+
+        if (info != null && info.getType() == ConnectivityManager.TYPE_BLUETOOTH) {
+            mBluetoothTethered = info.isConnected();
+        } else {
+            mBluetoothTethered = false;
+        }
+
+        // We want to update all the icons, all at once, for any condition change
+        updateDataNetType();
+        updateWimaxIcons();
+        updateDataIcon();
+        updateTelephonySignalStrength();
+        updateWifiIcons();
+    }
+
+
+    // ===== Update the views =======================================================
+
+    void refreshViews() {
+        Context context = mContext;
+
+        int combinedSignalIconId = 0;
+        String combinedLabel = "";
+        String wifiLabel = "";
+        String mobileLabel = "";
+        int N;
+        final boolean emergencyOnly = isEmergencyOnly();
+
+        if (!mHasMobileDataFeature) {
+            mDataSignalIconId = mPhoneSignalIconId = 0;
+            mQSPhoneSignalIconId = 0;
+            mobileLabel = "";
+        } else {
+            // We want to show the carrier name if in service and either:
+            //   - We are connected to mobile data, or
+            //   - We are not connected to mobile data, as long as the *reason* packets are not
+            //     being routed over that link is that we have better connectivity via wifi.
+            // If data is disconnected for some other reason but wifi (or ethernet/bluetooth)
+            // is connected, we show nothing.
+            // Otherwise (nothing connected) we show "No internet connection".
+
+            if (mDataConnected) {
+                mobileLabel = mNetworkName;
+            } else if (mConnected || emergencyOnly) {
+                if (hasService() || emergencyOnly) {
+                    // The isEmergencyOnly test covers the case of a phone with no SIM
+                    mobileLabel = mNetworkName;
+                } else {
+                    // Tablets, basically
+                    mobileLabel = "";
+                }
+            } else {
+                mobileLabel
+                    = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
+            }
+
+            // Now for things that should only be shown when actually using mobile data.
+            if (mDataConnected) {
+                combinedSignalIconId = mDataSignalIconId;
+
+                combinedLabel = mobileLabel;
+                combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon()
+                mContentDescriptionCombinedSignal = mContentDescriptionDataType;
+            }
+        }
+
+        if (mWifiConnected) {
+            if (mWifiSsid == null) {
+                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid);
+            } else {
+                wifiLabel = mWifiSsid;
+                if (DEBUG) {
+                    wifiLabel += "xxxxXXXXxxxxXXXX";
+                }
+            }
+
+            combinedLabel = wifiLabel;
+            combinedSignalIconId = mWifiIconId; // set by updateWifiIcons()
+            mContentDescriptionCombinedSignal = mContentDescriptionWifi;
+        } else {
+            if (mHasMobileDataFeature) {
+                wifiLabel = "";
+            } else {
+                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
+            }
+        }
+
+        if (mBluetoothTethered) {
+            combinedLabel = mContext.getString(R.string.bluetooth_tethered);
+            combinedSignalIconId = mBluetoothTetherIconId;
+            mContentDescriptionCombinedSignal = mContext.getString(
+                    R.string.accessibility_bluetooth_tether);
+        }
+
+        final boolean ethernetConnected = (mConnectedNetworkType == ConnectivityManager.TYPE_ETHERNET);
+        if (ethernetConnected) {
+            combinedLabel = context.getString(R.string.ethernet_label);
+        }
+
+        if (mAirplaneMode &&
+                (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) {
+            // Only display the flight-mode icon if not in "emergency calls only" mode.
+
+            // look again; your radios are now airplanes
+            mContentDescriptionPhoneSignal = mContext.getString(
+                    R.string.accessibility_airplane_mode);
+            mAirplaneIconId = FLIGHT_MODE_ICON;
+            mPhoneSignalIconId = mDataSignalIconId = mDataTypeIconId = mQSDataTypeIconId = 0;
+            mQSPhoneSignalIconId = 0;
+
+            // combined values from connected wifi take precedence over airplane mode
+            if (mWifiConnected) {
+                // Suppress "No internet connection." from mobile if wifi connected.
+                mobileLabel = "";
+            } else {
+                if (mHasMobileDataFeature) {
+                    // let the mobile icon show "No internet connection."
+                    wifiLabel = "";
+                } else {
+                    wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
+                    combinedLabel = wifiLabel;
+                }
+                mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal;
+                combinedSignalIconId = mDataSignalIconId;
+            }
+        }
+        else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected && !ethernetConnected) {
+            // pretty much totally disconnected
+
+            combinedLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
+            // On devices without mobile radios, we want to show the wifi icon
+            combinedSignalIconId =
+                mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId;
+            mContentDescriptionCombinedSignal = mHasMobileDataFeature
+                ? mContentDescriptionDataType : mContentDescriptionWifi;
+
+            mDataTypeIconId = 0;
+            mQSDataTypeIconId = 0;
+            if (isCdma()) {
+                if (isCdmaEri()) {
+                    mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
+                }
+            } else if (mPhone.isNetworkRoaming()) {
+                mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
+            }
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "refreshViews connected={"
+                    + (mWifiConnected?" wifi":"")
+                    + (mDataConnected?" data":"")
+                    + " } level="
+                    + ((mSignalStrength == null)?"??":Integer.toString(mSignalStrength.getLevel()))
+                    + " combinedSignalIconId=0x"
+                    + Integer.toHexString(combinedSignalIconId)
+                    + "/" + getResourceName(combinedSignalIconId)
+                    + " mobileLabel=" + mobileLabel
+                    + " wifiLabel=" + wifiLabel
+                    + " emergencyOnly=" + emergencyOnly
+                    + " combinedLabel=" + combinedLabel
+                    + " mAirplaneMode=" + mAirplaneMode
+                    + " mDataActivity=" + mDataActivity
+                    + " mPhoneSignalIconId=0x" + Integer.toHexString(mPhoneSignalIconId)
+                    + " mQSPhoneSignalIconId=0x" + Integer.toHexString(mQSPhoneSignalIconId)
+                    + " mDataDirectionIconId=0x" + Integer.toHexString(mDataDirectionIconId)
+                    + " mDataSignalIconId=0x" + Integer.toHexString(mDataSignalIconId)
+                    + " mDataTypeIconId=0x" + Integer.toHexString(mDataTypeIconId)
+                    + " mQSDataTypeIconId=0x" + Integer.toHexString(mQSDataTypeIconId)
+                    + " mWifiIconId=0x" + Integer.toHexString(mWifiIconId)
+                    + " mQSWifiIconId=0x" + Integer.toHexString(mQSWifiIconId)
+                    + " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId));
+        }
+
+        // update QS
+        for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) {
+            notifySignalsChangedCallbacks(cb);
+        }
+
+        if (mLastPhoneSignalIconId          != mPhoneSignalIconId
+         || mLastWifiIconId                 != mWifiIconId
+         || mLastInetCondition              != mInetCondition
+         || mLastWimaxIconId                != mWimaxIconId
+         || mLastDataTypeIconId             != mDataTypeIconId
+         || mLastAirplaneMode               != mAirplaneMode
+         || mLastLocale                     != mLocale)
+        {
+            // NB: the mLast*s will be updated later
+            for (SignalCluster cluster : mSignalClusters) {
+                refreshSignalCluster(cluster);
+            }
+        }
+
+        if (mLastAirplaneMode != mAirplaneMode) {
+            mLastAirplaneMode = mAirplaneMode;
+        }
+
+        if (mLastLocale != mLocale) {
+            mLastLocale = mLocale;
+        }
+
+        // the phone icon on phones
+        if (mLastPhoneSignalIconId != mPhoneSignalIconId) {
+            mLastPhoneSignalIconId = mPhoneSignalIconId;
+        }
+
+        // the data icon on phones
+        if (mLastDataDirectionIconId != mDataDirectionIconId) {
+            mLastDataDirectionIconId = mDataDirectionIconId;
+        }
+
+        // the wifi icon on phones
+        if (mLastWifiIconId != mWifiIconId) {
+            mLastWifiIconId = mWifiIconId;
+        }
+
+        if (mLastInetCondition != mInetCondition) {
+            mLastInetCondition = mInetCondition;
+        }
+
+        // the wimax icon on phones
+        if (mLastWimaxIconId != mWimaxIconId) {
+            mLastWimaxIconId = mWimaxIconId;
+        }
+        // the combined data signal icon
+        if (mLastCombinedSignalIconId != combinedSignalIconId) {
+            mLastCombinedSignalIconId = combinedSignalIconId;
+        }
+
+        // the data network type overlay
+        if (mLastDataTypeIconId != mDataTypeIconId) {
+            mLastDataTypeIconId = mDataTypeIconId;
+        }
+
+        // the combinedLabel in the notification panel
+        if (!mLastCombinedLabel.equals(combinedLabel)) {
+            mLastCombinedLabel = combinedLabel;
+            N = mCombinedLabelViews.size();
+            for (int i=0; i<N; i++) {
+                TextView v = mCombinedLabelViews.get(i);
+                v.setText(combinedLabel);
+            }
+        }
+
+        // wifi label
+        N = mWifiLabelViews.size();
+        for (int i=0; i<N; i++) {
+            TextView v = mWifiLabelViews.get(i);
+            v.setText(wifiLabel);
+            if ("".equals(wifiLabel)) {
+                v.setVisibility(View.GONE);
+            } else {
+                v.setVisibility(View.VISIBLE);
+            }
+        }
+
+        // mobile label
+        N = mMobileLabelViews.size();
+        for (int i=0; i<N; i++) {
+            TextView v = mMobileLabelViews.get(i);
+            v.setText(mobileLabel);
+            if ("".equals(mobileLabel)) {
+                v.setVisibility(View.GONE);
+            } else {
+                v.setVisibility(View.VISIBLE);
+            }
+        }
+
+        // e-call label
+        N = mEmergencyLabelViews.size();
+        for (int i=0; i<N; i++) {
+            TextView v = mEmergencyLabelViews.get(i);
+            if (!emergencyOnly) {
+                v.setVisibility(View.GONE);
+            } else {
+                v.setText(mobileLabel); // comes from the telephony stack
+                v.setVisibility(View.VISIBLE);
+            }
+        }
+    }
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("NetworkController state:");
+        pw.println(String.format("  %s network type %d (%s)",
+                mConnected?"CONNECTED":"DISCONNECTED",
+                mConnectedNetworkType, mConnectedNetworkTypeName));
+        pw.println("  - telephony ------");
+        pw.print("  hasVoiceCallingFeature()=");
+        pw.println(hasVoiceCallingFeature());
+        pw.print("  hasService()=");
+        pw.println(hasService());
+        pw.print("  mHspaDataDistinguishable=");
+        pw.println(mHspaDataDistinguishable);
+        pw.print("  mDataConnected=");
+        pw.println(mDataConnected);
+        pw.print("  mSimState=");
+        pw.println(mSimState);
+        pw.print("  mPhoneState=");
+        pw.println(mPhoneState);
+        pw.print("  mDataState=");
+        pw.println(mDataState);
+        pw.print("  mDataActivity=");
+        pw.println(mDataActivity);
+        pw.print("  mDataNetType=");
+        pw.print(mDataNetType);
+        pw.print("/");
+        pw.println(TelephonyManager.getNetworkTypeName(mDataNetType));
+        pw.print("  mServiceState=");
+        pw.println(mServiceState);
+        pw.print("  mSignalStrength=");
+        pw.println(mSignalStrength);
+        pw.print("  mLastSignalLevel=");
+        pw.println(mLastSignalLevel);
+        pw.print("  mNetworkName=");
+        pw.println(mNetworkName);
+        pw.print("  mNetworkNameDefault=");
+        pw.println(mNetworkNameDefault);
+        pw.print("  mNetworkNameSeparator=");
+        pw.println(mNetworkNameSeparator.replace("\n","\\n"));
+        pw.print("  mPhoneSignalIconId=0x");
+        pw.print(Integer.toHexString(mPhoneSignalIconId));
+        pw.print("/");
+        pw.print("  mQSPhoneSignalIconId=0x");
+        pw.print(Integer.toHexString(mQSPhoneSignalIconId));
+        pw.print("/");
+        pw.println(getResourceName(mPhoneSignalIconId));
+        pw.print("  mDataDirectionIconId=");
+        pw.print(Integer.toHexString(mDataDirectionIconId));
+        pw.print("/");
+        pw.println(getResourceName(mDataDirectionIconId));
+        pw.print("  mDataSignalIconId=");
+        pw.print(Integer.toHexString(mDataSignalIconId));
+        pw.print("/");
+        pw.println(getResourceName(mDataSignalIconId));
+        pw.print("  mDataTypeIconId=");
+        pw.print(Integer.toHexString(mDataTypeIconId));
+        pw.print("/");
+        pw.println(getResourceName(mDataTypeIconId));
+        pw.print("  mQSDataTypeIconId=");
+        pw.print(Integer.toHexString(mQSDataTypeIconId));
+        pw.print("/");
+        pw.println(getResourceName(mQSDataTypeIconId));
+
+        pw.println("  - wifi ------");
+        pw.print("  mWifiEnabled=");
+        pw.println(mWifiEnabled);
+        pw.print("  mWifiConnected=");
+        pw.println(mWifiConnected);
+        pw.print("  mWifiRssi=");
+        pw.println(mWifiRssi);
+        pw.print("  mWifiLevel=");
+        pw.println(mWifiLevel);
+        pw.print("  mWifiSsid=");
+        pw.println(mWifiSsid);
+        pw.println(String.format("  mWifiIconId=0x%08x/%s",
+                    mWifiIconId, getResourceName(mWifiIconId)));
+        pw.println(String.format("  mQSWifiIconId=0x%08x/%s",
+                    mQSWifiIconId, getResourceName(mQSWifiIconId)));
+        pw.print("  mWifiActivity=");
+        pw.println(mWifiActivity);
+
+        if (mWimaxSupported) {
+            pw.println("  - wimax ------");
+            pw.print("  mIsWimaxEnabled="); pw.println(mIsWimaxEnabled);
+            pw.print("  mWimaxConnected="); pw.println(mWimaxConnected);
+            pw.print("  mWimaxIdle="); pw.println(mWimaxIdle);
+            pw.println(String.format("  mWimaxIconId=0x%08x/%s",
+                        mWimaxIconId, getResourceName(mWimaxIconId)));
+            pw.println(String.format("  mWimaxSignal=%d", mWimaxSignal));
+            pw.println(String.format("  mWimaxState=%d", mWimaxState));
+            pw.println(String.format("  mWimaxExtraState=%d", mWimaxExtraState));
+        }
+
+        pw.println("  - Bluetooth ----");
+        pw.print("  mBtReverseTethered=");
+        pw.println(mBluetoothTethered);
+
+        pw.println("  - connectivity ------");
+        pw.print("  mInetCondition=");
+        pw.println(mInetCondition);
+
+        pw.println("  - icons ------");
+        pw.print("  mLastPhoneSignalIconId=0x");
+        pw.print(Integer.toHexString(mLastPhoneSignalIconId));
+        pw.print("/");
+        pw.println(getResourceName(mLastPhoneSignalIconId));
+        pw.print("  mLastDataDirectionIconId=0x");
+        pw.print(Integer.toHexString(mLastDataDirectionIconId));
+        pw.print("/");
+        pw.println(getResourceName(mLastDataDirectionIconId));
+        pw.print("  mLastWifiIconId=0x");
+        pw.print(Integer.toHexString(mLastWifiIconId));
+        pw.print("/");
+        pw.println(getResourceName(mLastWifiIconId));
+        pw.print("  mLastCombinedSignalIconId=0x");
+        pw.print(Integer.toHexString(mLastCombinedSignalIconId));
+        pw.print("/");
+        pw.println(getResourceName(mLastCombinedSignalIconId));
+        pw.print("  mLastDataTypeIconId=0x");
+        pw.print(Integer.toHexString(mLastDataTypeIconId));
+        pw.print("/");
+        pw.println(getResourceName(mLastDataTypeIconId));
+        pw.print("  mLastCombinedLabel=");
+        pw.print(mLastCombinedLabel);
+        pw.println("");
+    }
+
+    private String getResourceName(int resId) {
+        if (resId != 0) {
+            final Resources res = mContext.getResources();
+            try {
+                return res.getResourceName(resId);
+            } catch (android.content.res.Resources.NotFoundException ex) {
+                return "(unknown)";
+            }
+        } else {
+            return "(null)";
+        }
+    }
+
+    private boolean mDemoMode;
+    private int mDemoInetCondition;
+    private int mDemoWifiLevel;
+    private int mDemoDataTypeIconId;
+    private int mDemoMobileLevel;
+
+    @Override
+    public void dispatchDemoCommand(String command, Bundle args) {
+        if (!mDemoMode && command.equals(COMMAND_ENTER)) {
+            mDemoMode = true;
+            mDemoWifiLevel = mWifiLevel;
+            mDemoInetCondition = mInetCondition;
+            mDemoDataTypeIconId = mDataTypeIconId;
+            mDemoMobileLevel = mLastSignalLevel;
+        } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
+            mDemoMode = false;
+            for (SignalCluster cluster : mSignalClusters) {
+                refreshSignalCluster(cluster);
+            }
+        } else if (mDemoMode && command.equals(COMMAND_NETWORK)) {
+            String airplane = args.getString("airplane");
+            if (airplane != null) {
+                boolean show = airplane.equals("show");
+                for (SignalCluster cluster : mSignalClusters) {
+                    cluster.setIsAirplaneMode(show, FLIGHT_MODE_ICON);
+                }
+            }
+            String fully = args.getString("fully");
+            if (fully != null) {
+                mDemoInetCondition = Boolean.parseBoolean(fully) ? 1 : 0;
+            }
+            String wifi = args.getString("wifi");
+            if (wifi != null) {
+                boolean show = wifi.equals("show");
+                String level = args.getString("level");
+                if (level != null) {
+                    mDemoWifiLevel = level.equals("null") ? -1
+                            : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
+                }
+                int iconId = mDemoWifiLevel < 0 ? R.drawable.stat_sys_wifi_signal_null
+                        : WifiIcons.WIFI_SIGNAL_STRENGTH[mDemoInetCondition][mDemoWifiLevel];
+                for (SignalCluster cluster : mSignalClusters) {
+                    cluster.setWifiIndicators(
+                            show,
+                            iconId,
+                            mDemoInetCondition == 0,
+                            "Demo");
+                }
+            }
+            String mobile = args.getString("mobile");
+            if (mobile != null) {
+                boolean show = mobile.equals("show");
+                String datatype = args.getString("datatype");
+                if (datatype != null) {
+                    mDemoDataTypeIconId =
+                            datatype.equals("1x") ? R.drawable.stat_sys_data_fully_connected_1x :
+                            datatype.equals("3g") ? R.drawable.stat_sys_data_fully_connected_3g :
+                            datatype.equals("4g") ? R.drawable.stat_sys_data_fully_connected_4g :
+                            datatype.equals("e") ? R.drawable.stat_sys_data_fully_connected_e :
+                            datatype.equals("g") ? R.drawable.stat_sys_data_fully_connected_g :
+                            datatype.equals("h") ? R.drawable.stat_sys_data_fully_connected_h :
+                            datatype.equals("lte") ? R.drawable.stat_sys_data_fully_connected_lte :
+                            datatype.equals("roam")
+                                    ? R.drawable.stat_sys_data_fully_connected_roam :
+                            0;
+                }
+                int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
+                String level = args.getString("level");
+                if (level != null) {
+                    mDemoMobileLevel = level.equals("null") ? -1
+                            : Math.min(Integer.parseInt(level), icons[0].length - 1);
+                }
+                int iconId = mDemoMobileLevel < 0 ? R.drawable.stat_sys_signal_null :
+                        icons[mDemoInetCondition][mDemoMobileLevel];
+                for (SignalCluster cluster : mSignalClusters) {
+                    cluster.setMobileDataIndicators(
+                            show,
+                            iconId,
+                            mDemoInetCondition == 0,
+                            mDemoDataTypeIconId,
+                            "Demo",
+                            "Demo");
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
index 98d205a..1eb678d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * 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.
@@ -16,65 +16,15 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.content.Context;
-import android.content.res.Configuration;
-import android.os.UserHandle;
-
-import com.android.internal.view.RotationPolicy;
-
-import java.util.concurrent.CopyOnWriteArrayList;
-
-public final class RotationLockController {
-    private final Context mContext;
-    private final CopyOnWriteArrayList<RotationLockControllerCallback> mCallbacks =
-            new CopyOnWriteArrayList<RotationLockControllerCallback>();
-
-    private final RotationPolicy.RotationPolicyListener mRotationPolicyListener =
-            new RotationPolicy.RotationPolicyListener() {
-        @Override
-        public void onChange() {
-            notifyChanged();
-        }
-    };
+public interface RotationLockController extends Disposable {
+    int getRotationLockOrientation();
+    boolean isRotationLockAffordanceVisible();
+    boolean isRotationLocked();
+    void setRotationLocked(boolean locked);
+    void addRotationLockControllerCallback(RotationLockControllerCallback callback);
+    void removeRotationLockControllerCallback(RotationLockControllerCallback callback);
 
     public interface RotationLockControllerCallback {
-        public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible);
-    }
-
-    public RotationLockController(Context context) {
-        mContext = context;
-        RotationPolicy.registerRotationPolicyListener(mContext,
-                mRotationPolicyListener, UserHandle.USER_ALL);
-    }
-
-    public void addRotationLockControllerCallback(RotationLockControllerCallback callback) {
-        mCallbacks.add(callback);
-    }
-
-    public int getRotationLockOrientation() {
-        return RotationPolicy.getRotationLockOrientation(mContext);
-    }
-
-    public boolean isRotationLocked() {
-        return RotationPolicy.isRotationLocked(mContext);
-    }
-
-    public void setRotationLocked(boolean locked) {
-        RotationPolicy.setRotationLock(mContext, locked);
-    }
-
-    public boolean isRotationLockAffordanceVisible() {
-        return RotationPolicy.isRotationLockToggleVisible(mContext);
-    }
-
-    public void release() {
-        RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener);
-    }
-
-    private void notifyChanged() {
-        for (RotationLockControllerCallback callback : mCallbacks) {
-            callback.onRotationLockStateChanged(RotationPolicy.isRotationLocked(mContext),
-                    RotationPolicy.isRotationLockToggleVisible(mContext));
-        }
+        void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
new file mode 100644
index 0000000..caa07ef
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010 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.statusbar.policy;
+
+import android.content.Context;
+import android.os.UserHandle;
+
+import com.android.internal.view.RotationPolicy;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/** Platform implementation of the rotation lock controller. **/
+public final class RotationLockControllerImpl implements RotationLockController {
+    private final Context mContext;
+    private final CopyOnWriteArrayList<RotationLockControllerCallback> mCallbacks =
+            new CopyOnWriteArrayList<RotationLockControllerCallback>();
+
+    private final RotationPolicy.RotationPolicyListener mRotationPolicyListener =
+            new RotationPolicy.RotationPolicyListener() {
+        @Override
+        public void onChange() {
+            notifyChanged();
+        }
+    };
+
+    public RotationLockControllerImpl(Context context) {
+        mContext = context;
+        RotationPolicy.registerRotationPolicyListener(mContext,
+                mRotationPolicyListener, UserHandle.USER_ALL);
+    }
+
+    public void addRotationLockControllerCallback(RotationLockControllerCallback callback) {
+        mCallbacks.add(callback);
+    }
+
+    public void removeRotationLockControllerCallback(RotationLockControllerCallback callback) {
+        mCallbacks.remove(callback);
+    }
+
+    public int getRotationLockOrientation() {
+        return RotationPolicy.getRotationLockOrientation(mContext);
+    }
+
+    public boolean isRotationLocked() {
+        return RotationPolicy.isRotationLocked(mContext);
+    }
+
+    public void setRotationLocked(boolean locked) {
+        RotationPolicy.setRotationLock(mContext, locked);
+    }
+
+    public boolean isRotationLockAffordanceVisible() {
+        return RotationPolicy.isRotationLockToggleVisible(mContext);
+    }
+
+    @Override
+    public void dispose() {
+        RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener);
+    }
+
+    private void notifyChanged() {
+        for (RotationLockControllerCallback callback : mCallbacks) {
+            callback.onRotationLockStateChanged(RotationPolicy.isRotationLocked(mContext),
+                    RotationPolicy.isRotationLockToggleVisible(mContext));
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TetheringController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TetheringController.java
new file mode 100644
index 0000000..143ebaa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TetheringController.java
@@ -0,0 +1,28 @@
+/*
+ * 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.statusbar.policy;
+
+public interface TetheringController {
+    void addCallback(Callback callback);
+    void removeCallback(Callback callback);
+    boolean isHotspotEnabled();
+    boolean isHotspotSupported();
+
+    public interface Callback {
+        void onHotspotChanged(boolean hotspot);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
new file mode 100644
index 0000000..6225c12
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -0,0 +1,33 @@
+/*
+ * 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.statusbar.policy;
+
+import android.service.notification.Condition;
+
+public interface ZenModeController {
+    void addCallback(Callback callback);
+    void removeCallback(Callback callback);
+    void setZen(boolean zen);
+    boolean isZen();
+    void requestConditions(boolean request);
+    void select(Condition condition);
+
+    public static class Callback {
+        public void onZenChanged(boolean zen) {}
+        public void onConditionsChanged(Condition[] conditions) {}
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
new file mode 100644
index 0000000..d760f78
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -0,0 +1,132 @@
+/*
+ * 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.statusbar.policy;
+
+import android.app.INotificationManager;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings.Global;
+import android.service.notification.Condition;
+import android.service.notification.IConditionListener;
+import android.util.Slog;
+
+import com.android.systemui.qs.GlobalSetting;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+
+/** Platform implementation of the zen mode controller. **/
+public class ZenModeControllerImpl implements ZenModeController {
+    private static final String TAG = "ZenModeControllerImpl";
+
+    private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
+    private final Context mContext;
+    private final GlobalSetting mSetting;
+    private final INotificationManager mNoMan;
+    private final LinkedHashMap<Uri, Condition> mConditions = new LinkedHashMap<Uri, Condition>();
+
+    private boolean mRequesting;
+
+    public ZenModeControllerImpl(Context context, Handler handler) {
+        mContext = context;
+        mSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE) {
+            @Override
+            protected void handleValueChanged(int value) {
+                fireZenChanged(value != 0);
+            }
+        };
+        mNoMan = INotificationManager.Stub.asInterface(
+                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+    }
+
+    @Override
+    public void addCallback(Callback callback) {
+        mCallbacks.add(callback);
+    }
+
+    @Override
+    public void removeCallback(Callback callback) {
+        mCallbacks.remove(callback);
+    }
+
+    @Override
+    public boolean isZen() {
+        return mSetting.getValue() != 0;
+    }
+
+    @Override
+    public void setZen(boolean zen) {
+        mSetting.setValue(zen ? 1 : 0);
+    }
+
+    @Override
+    public void requestConditions(boolean request) {
+        mRequesting = request;
+        try {
+            mNoMan.requestZenModeConditions(mListener, request ? Condition.FLAG_RELEVANT_NOW : 0);
+        } catch (RemoteException e) {
+            // noop
+        }
+        if (!mRequesting) {
+            mConditions.clear();
+        }
+    }
+
+    @Override
+    public void select(Condition condition) {
+        try {
+            mNoMan.setZenModeCondition(condition == null ? null : condition.id);
+        } catch (RemoteException e) {
+            // noop
+        }
+    }
+
+    private void fireZenChanged(boolean zen) {
+        for (Callback cb : mCallbacks) {
+            cb.onZenChanged(zen);
+        }
+    }
+
+    private void fireConditionsChanged(Condition[] conditions) {
+        for (Callback cb : mCallbacks) {
+            cb.onConditionsChanged(conditions);
+        }
+    }
+
+    private void updateConditions(Condition[] conditions) {
+        if (conditions == null || conditions.length == 0) return;
+        for (Condition c : conditions) {
+            if ((c.flags & Condition.FLAG_RELEVANT_NOW) == 0) continue;
+            mConditions.put(c.id, c);
+        }
+        fireConditionsChanged(
+                mConditions.values().toArray(new Condition[mConditions.values().size()]));
+    }
+
+    private final IConditionListener mListener = new IConditionListener.Stub() {
+        @Override
+        public void onConditionsReceived(Condition[] conditions) {
+            Slog.d(TAG, "onConditionsReceived " + (conditions == null ? 0 : conditions.length)
+                    + " mRequesting=" + mRequesting); 
+            if (!mRequesting) return;
+            updateConditions(conditions);
+        }
+    };
+}