summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_airplane.xml31
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_bluetooth.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_bugreport.xml31
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_cast.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_close.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_hotspot.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_invert_colors.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_location.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_minus.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_plus.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_rotation.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_rotation_lock.xml34
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_rotation_locked_landscape.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_rotation_locked_portrait.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_zen.xml28
-rw-r--r--packages/SystemUI/res/drawable/qs_panel_background.xml (renamed from packages/SystemUI/res/layout/quick_settings_tile_media.xml)19
-rw-r--r--packages/SystemUI/res/layout/flip_settings.xml25
-rw-r--r--packages/SystemUI/res/layout/qs_panel.xml28
-rw-r--r--packages/SystemUI/res/layout/qs_zen_mode_detail.xml76
-rw-r--r--packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml57
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile.xml20
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_alarm.xml25
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_basic.xml39
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_battery.xml41
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_ime.xml26
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_monitoring.xml39
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_rssi.xml71
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_user.xml36
-rw-r--r--packages/SystemUI/res/layout/quick_settings_tile_wifi.xml57
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml2
-rw-r--r--packages/SystemUI/res/values-land/config.xml2
-rw-r--r--packages/SystemUI/res/values-sw600dp/config.xml2
-rw-r--r--packages/SystemUI/res/values/colors.xml8
-rw-r--r--packages/SystemUI/res/values/dimens.xml4
-rw-r--r--packages/SystemUI/res/values/strings.xml8
-rw-r--r--packages/SystemUI/res/values/styles.xml12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/CircularClipper.java74
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java79
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java58
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSImageView.java102
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java247
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTile.java315
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileView.java190
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java62
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java112
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java100
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java93
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java103
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java123
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java153
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java78
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java82
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java105
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java81
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java148
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java279
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java83
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java111
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java178
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java1119
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java85
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java295
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java1047
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsScrollView.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java149
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java424
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java230
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java89
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java137
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java110
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java200
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java214
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java1453
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java1491
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java68
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java81
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/TetheringController.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java132
-rw-r--r--services/core/java/com/android/server/notification/ConditionProviders.java71
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java2
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java7
92 files changed, 6097 insertions, 5633 deletions
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/layout/quick_settings_tile_media.xml b/packages/SystemUI/res/drawable/qs_panel_background.xml
index 355176c..c324976 100644
--- a/packages/SystemUI/res/layout/quick_settings_tile_media.xml
+++ b/packages/SystemUI/res/drawable/qs_panel_background.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
@@ -13,12 +13,11 @@
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"
- />
+<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_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.ImageView;
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 @@ public class SignalClusterView
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.internal.statusbar.StatusBarIcon;
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 @@ public class DemoStatusIcons extends LinearLayout implements DemoMode {
}
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 @@ public class NotificationPanelView extends PanelView implements
PhoneStatusBar mStatusBar;
private StatusBarHeaderView mHeader;
- private QuickSettingsContainerView mQsContainer;
+ private View mQsContainer;
private View mKeyguardStatusView;
private ObservableScrollView mScrollView;
private View mStackScrollerContainer;
@@ -106,7 +106,7 @@ public class NotificationPanelView extends PanelView implements
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.DemoMode;
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.SignalClusterView;
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 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
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 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
TextView mNotificationPanelDebugText;
// settings
- QuickSettings mQS;
View mFlipSettingsView;
- QuickSettingsContainerView mSettingsContainer;
+ private QSPanel mQSPanel;
// top bar
StatusBarHeaderView mHeader;
@@ -660,15 +665,16 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
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 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// 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 class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
- public Handler getHandler() {
+ private Handler getHandler() {
return mHandler;
}
@@ -1514,6 +1519,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
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 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
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 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
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 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
setNavigationIconHints(flags);
- if (mQS != null) mQS.setImeWindowStatus(vis > 0);
}
@Override
@@ -2383,11 +2397,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
* 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 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
|| (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 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
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.LinearLayout;
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 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
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 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
updateVisibilities();
updateSystemIconsLayoutParams();
updateBrightnessControllerState();
+ if (mQSPanel != null) {
+ mQSPanel.setExpanded(expanded);
+ }
}
}
@@ -259,4 +264,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
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 @@ public class LocationController extends BroadcastReceiver {
* @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 @@ public class NetworkController extends BroadcastReceiver implements DemoMode {
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);
+ }
+ };
+}
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index d074565..007032e 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -16,8 +16,13 @@
package com.android.server.notification;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
@@ -30,6 +35,7 @@ import android.service.notification.ConditionProviderService;
import android.service.notification.IConditionListener;
import android.service.notification.IConditionProvider;
import android.service.notification.ZenModeConfig;
+import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
@@ -39,6 +45,7 @@ import com.android.internal.R;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Date;
public class ConditionProviders extends ManagedServices {
private static final Condition[] NO_CONDITIONS = new Condition[0];
@@ -47,6 +54,7 @@ public class ConditionProviders extends ManagedServices {
private final ArrayMap<IBinder, IConditionListener> mListeners
= new ArrayMap<IBinder, IConditionListener>();
private final ArrayList<ConditionRecord> mRecords = new ArrayList<ConditionRecord>();
+ private final CountdownConditionHelper mCountdownHelper = new CountdownConditionHelper();
public ConditionProviders(Context context, Handler handler,
UserProfiles userProfiles, ZenModeHelper zenModeHelper) {
@@ -267,6 +275,7 @@ public class ConditionProviders extends ManagedServices {
}
}
}
+ mCountdownHelper.setZenModeCondition(conditionId);
}
private void subscribeLocked(ConditionRecord r) {
@@ -434,6 +443,68 @@ public class ConditionProviders extends ManagedServices {
mZenModeHelper.setConfig(config);
}
+ private final class CountdownConditionHelper extends BroadcastReceiver {
+ private static final String ACTION = "CountdownConditionHelper";
+ private static final int REQUEST_CODE = 100;
+ private static final String EXTRA_TIME = "time";
+
+ private long mCurrent;
+
+ public CountdownConditionHelper() {
+ mContext.registerReceiver(this, new IntentFilter(ACTION));
+ }
+
+ public void setZenModeCondition(Uri conditionId) {
+ final long time = tryParseCondition(conditionId);
+ final AlarmManager alarms = (AlarmManager)
+ mContext.getSystemService(Context.ALARM_SERVICE);
+ final Intent intent = new Intent(ACTION).putExtra(EXTRA_TIME, time)
+ .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, REQUEST_CODE,
+ intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ alarms.cancel(pendingIntent);
+ mCurrent = time;
+ if (time > 0) {
+ final long now = System.currentTimeMillis();
+ final CharSequence span =
+ DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS);
+ Slog.d(TAG, String.format("Scheduling %s for %s, %s in the future (%s), now=%s",
+ ACTION, ts(time), time - now, span, ts(now)));
+ alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
+ }
+ }
+
+ private String ts(long time) {
+ return new Date(time) + " (" + time + ")";
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION.equals(intent.getAction())) {
+ final long time = intent.getLongExtra(EXTRA_TIME, 0);
+ Slog.d(TAG, "Countdown condition fired. time=" + time + " mCurrent=" + mCurrent);
+ if (time > 0 && time == mCurrent) {
+ // countdown condition is still the manual condition, leave zen
+ mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF);
+ ConditionProviders.this.setZenModeCondition(null);
+ }
+ }
+ }
+
+ private long tryParseCondition(Uri conditionId) {
+ // condition://android/countdown/1399917958951
+ if (!Condition.isValidId(conditionId, "android")) return 0;
+ if (conditionId.getPathSegments().size() != 2
+ || !"countdown".equals(conditionId.getPathSegments().get(0))) return 0;
+ try {
+ return Long.parseLong(conditionId.getPathSegments().get(1));
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Error parsing countdown condition: " + conditionId, e);
+ return 0;
+ }
+ }
+ }
+
private class ZenModeHelperCallback extends ZenModeHelper.Callback {
@Override
void onConfigChanged() {
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index d34b09c..584145f 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -66,7 +66,7 @@ abstract public class ManagedServices {
private static final String ENABLED_SERVICES_SEPARATOR = ":";
- private final Context mContext;
+ protected final Context mContext;
protected final Object mMutex;
private final UserProfiles mUserProfiles;
private final SettingsObserver mSettingsObserver;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7a4f951..f1c05ac 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1401,7 +1401,12 @@ public class NotificationManagerService extends SystemService {
@Override
public void setZenModeCondition(Uri conditionId) {
enforceSystemOrSystemUI("INotificationManager.setZenModeCondition");
- mConditionProviders.setZenModeCondition(conditionId);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mConditionProviders.setZenModeCondition(conditionId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override