summaryrefslogtreecommitdiffstats
path: root/packages/SystemUI
diff options
context:
space:
mode:
Diffstat (limited to 'packages/SystemUI')
-rw-r--r--packages/SystemUI/Android.mk2
-rw-r--r--packages/SystemUI/AndroidManifest.xml7
-rw-r--r--packages/SystemUI/proguard.flags4
-rw-r--r--packages/SystemUI/res/drawable-hdpi/battery_0.pngbin0 -> 4189 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/battery_100.pngbin0 -> 5931 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/battery_20.pngbin0 -> 4766 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/battery_40.pngbin0 -> 5632 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/battery_60.pngbin0 -> 5937 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/battery_80.pngbin0 -> 6075 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/button_frame_default.9.pngbin0 -> 2878 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/button_frame_pressed.9.pngbin0 -> 5583 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/dots_empty.pngbin0 -> 1584 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/dots_full.pngbin0 -> 2256 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/notification_dragger.pngbin0 -> 2022 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/signal_0.pngbin0 -> 4187 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/signal_100.pngbin0 -> 6102 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/signal_20.pngbin0 -> 5082 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/signal_40.pngbin0 -> 5803 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/signal_60.pngbin0 -> 6091 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/signal_80.pngbin0 -> 6281 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_back_default.pngbin0 -> 4276 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_back_pressed.pngbin0 -> 8409 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_expand_default.pngbin0 -> 1790 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_expand_pressed.pngbin0 -> 4328 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_home_default.pngbin0 -> 4384 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_home_pressed.pngbin0 -> 8855 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_icon_tray.9.pngbin0 -> 5030 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_menu_default.pngbin0 -> 5931 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_menu_pressed.pngbin0 -> 9439 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_veto_normal.pngbin0 -> 1221 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_veto_pressed.pngbin0 -> 1874 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/system_panel_airplane_default.pngbin0 -> 4960 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/system_panel_brightness_default.pngbin0 -> 6073 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/system_panel_orientation_default.pngbin0 -> 5144 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/system_panel_orientation_locked.pngbin0 -> 4923 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/system_panel_sound_default.pngbin0 -> 3294 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/battery_0.pngbin0 -> 1596 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/battery_100.pngbin0 -> 3955 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/battery_20.pngbin0 -> 3479 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/battery_40.pngbin0 -> 3937 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/battery_60.pngbin0 -> 3955 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/battery_80.pngbin0 -> 4020 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/button_frame_default.9.pngbin0 -> 1550 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/button_frame_pressed.9.pngbin0 -> 2842 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/dots_empty.pngbin0 -> 811 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/dots_full.pngbin0 -> 1257 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/notification_dragger.pngbin0 -> 3495 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/signal_0.pngbin0 -> 1596 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/signal_100.pngbin0 -> 4293 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/signal_20.pngbin0 -> 3693 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/signal_40.pngbin0 -> 3944 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/signal_60.pngbin0 -> 4123 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/signal_80.pngbin0 -> 4239 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/status_bar_back_default.pngbin0 -> 2372 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/status_bar_back_pressed.pngbin0 -> 4158 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/status_bar_expand_default.pngbin0 -> 1426 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/status_bar_expand_pressed.pngbin0 -> 2265 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/status_bar_home_default.pngbin0 -> 2369 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/status_bar_home_pressed.pngbin0 -> 4645 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/status_bar_icon_tray.9.pngbin0 -> 2200 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/status_bar_menu_default.pngbin0 -> 3172 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/status_bar_menu_pressed.pngbin0 -> 4532 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/status_bar_veto_normal.pngbin0 -> 699 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/status_bar_veto_pressed.pngbin0 -> 1192 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/system_panel_airplane_default.pngbin0 -> 3028 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/system_panel_brightness_default.pngbin0 -> 3683 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/system_panel_orientation_default.pngbin0 -> 3829 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/system_panel_orientation_locked.pngbin0 -> 3447 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/system_panel_sound_default.pngbin0 -> 2040 bytes
-rw-r--r--packages/SystemUI/res/drawable/battery.xml35
-rw-r--r--packages/SystemUI/res/drawable/battery_charging.xml54
-rw-r--r--packages/SystemUI/res/drawable/button_frame.xml21
-rw-r--r--packages/SystemUI/res/drawable/signal.xml30
-rw-r--r--packages/SystemUI/res/drawable/status_bar_back.xml21
-rw-r--r--packages/SystemUI/res/drawable/status_bar_expand.xml21
-rw-r--r--packages/SystemUI/res/drawable/status_bar_home.xml21
-rw-r--r--packages/SystemUI/res/drawable/status_bar_menu.xml21
-rw-r--r--packages/SystemUI/res/drawable/status_bar_veto.xml21
-rw-r--r--packages/SystemUI/res/layout-xlarge/status_bar.xml137
-rw-r--r--packages/SystemUI/res/layout-xlarge/status_bar_center.xml56
-rw-r--r--packages/SystemUI/res/layout-xlarge/status_bar_latest_event.xml36
-rw-r--r--packages/SystemUI/res/layout-xlarge/sysbar_panel_notifications.xml68
-rw-r--r--packages/SystemUI/res/layout-xlarge/sysbar_panel_system.xml147
-rw-r--r--packages/SystemUI/res/layout/status_bar.xml1
-rw-r--r--packages/SystemUI/res/values-xlarge/colors.xml5
-rw-r--r--packages/SystemUI/res/values-xlarge/config.xml25
-rw-r--r--packages/SystemUI/res/values-xlarge/strings.xml23
-rw-r--r--packages/SystemUI/res/values/attrs.xml22
-rw-r--r--packages/SystemUI/res/values/config.xml11
-rw-r--r--packages/SystemUI/res/values/strings.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyButtonView.java122
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java81
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java1551
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java1532
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/TickerView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationIconArea.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/SystemPanel.java403
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java698
104 files changed, 3718 insertions, 1565 deletions
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 4c83768..910e84e 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -10,4 +10,6 @@ LOCAL_JAVA_LIBRARIES := services
LOCAL_PACKAGE_NAME := SystemUI
LOCAL_CERTIFICATE := platform
+LOCAL_PROGUARD_FLAGS := -include $(LOCAL_PATH)/proguard.flags
+
include $(BUILD_PACKAGE)
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 0fccbe7..7bc2e7d 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -13,7 +13,12 @@
android:icon="@drawable/ic_launcher_settings">
<service
- android:name=".statusbar.StatusBarService"
+ android:name=".statusbar.PhoneStatusBarService"
+ android:exported="false"
+ />
+
+ <service
+ android:name=".statusbar.tablet.TabletStatusBarService"
android:exported="false"
/>
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
new file mode 100644
index 0000000..9ccc5a9
--- /dev/null
+++ b/packages/SystemUI/proguard.flags
@@ -0,0 +1,4 @@
+-keep class com.android.systemui.statusbar.tablet.TabletStatusBarService {
+ public void notificationIconsClicked(android.view.View);
+ public void systemInfoClicked(android.view.View);
+}
diff --git a/packages/SystemUI/res/drawable-hdpi/battery_0.png b/packages/SystemUI/res/drawable-hdpi/battery_0.png
new file mode 100644
index 0000000..f4103a8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/battery_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/battery_100.png b/packages/SystemUI/res/drawable-hdpi/battery_100.png
new file mode 100644
index 0000000..061cbe5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/battery_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/battery_20.png b/packages/SystemUI/res/drawable-hdpi/battery_20.png
new file mode 100644
index 0000000..0064027
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/battery_20.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/battery_40.png b/packages/SystemUI/res/drawable-hdpi/battery_40.png
new file mode 100644
index 0000000..10de0e7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/battery_40.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/battery_60.png b/packages/SystemUI/res/drawable-hdpi/battery_60.png
new file mode 100644
index 0000000..aa2b8ef
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/battery_60.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/battery_80.png b/packages/SystemUI/res/drawable-hdpi/battery_80.png
new file mode 100644
index 0000000..fe231f0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/battery_80.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/button_frame_default.9.png b/packages/SystemUI/res/drawable-hdpi/button_frame_default.9.png
new file mode 100644
index 0000000..d809b84
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/button_frame_default.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/button_frame_pressed.9.png b/packages/SystemUI/res/drawable-hdpi/button_frame_pressed.9.png
new file mode 100644
index 0000000..5cc007c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/button_frame_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/dots_empty.png b/packages/SystemUI/res/drawable-hdpi/dots_empty.png
new file mode 100644
index 0000000..31e7654
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/dots_empty.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/dots_full.png b/packages/SystemUI/res/drawable-hdpi/dots_full.png
new file mode 100644
index 0000000..8c5c604
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/dots_full.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/notification_dragger.png b/packages/SystemUI/res/drawable-hdpi/notification_dragger.png
new file mode 100644
index 0000000..71b5507
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/notification_dragger.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/signal_0.png b/packages/SystemUI/res/drawable-hdpi/signal_0.png
new file mode 100644
index 0000000..00e36c4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/signal_100.png b/packages/SystemUI/res/drawable-hdpi/signal_100.png
new file mode 100644
index 0000000..96e52ff
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/signal_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/signal_20.png b/packages/SystemUI/res/drawable-hdpi/signal_20.png
new file mode 100644
index 0000000..c0f652a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/signal_20.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/signal_40.png b/packages/SystemUI/res/drawable-hdpi/signal_40.png
new file mode 100644
index 0000000..995dd8e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/signal_40.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/signal_60.png b/packages/SystemUI/res/drawable-hdpi/signal_60.png
new file mode 100644
index 0000000..51e31ba
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/signal_60.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/signal_80.png b/packages/SystemUI/res/drawable-hdpi/signal_80.png
new file mode 100644
index 0000000..afa656e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/signal_80.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_back_default.png b/packages/SystemUI/res/drawable-hdpi/status_bar_back_default.png
new file mode 100644
index 0000000..a9f9540
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_back_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_back_pressed.png b/packages/SystemUI/res/drawable-hdpi/status_bar_back_pressed.png
new file mode 100644
index 0000000..b8aa190
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_back_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_expand_default.png b/packages/SystemUI/res/drawable-hdpi/status_bar_expand_default.png
new file mode 100644
index 0000000..92fc7f8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_expand_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_expand_pressed.png b/packages/SystemUI/res/drawable-hdpi/status_bar_expand_pressed.png
new file mode 100644
index 0000000..77f09ac
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_expand_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_home_default.png b/packages/SystemUI/res/drawable-hdpi/status_bar_home_default.png
new file mode 100644
index 0000000..cb951dd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_home_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_home_pressed.png b/packages/SystemUI/res/drawable-hdpi/status_bar_home_pressed.png
new file mode 100644
index 0000000..a835ad5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_home_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_icon_tray.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_icon_tray.9.png
new file mode 100644
index 0000000..e1f041c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_icon_tray.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_menu_default.png b/packages/SystemUI/res/drawable-hdpi/status_bar_menu_default.png
new file mode 100644
index 0000000..14779cf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_menu_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_menu_pressed.png b/packages/SystemUI/res/drawable-hdpi/status_bar_menu_pressed.png
new file mode 100644
index 0000000..6c3d4c9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_menu_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_veto_normal.png b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_normal.png
new file mode 100644
index 0000000..df532b8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_veto_pressed.png b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_pressed.png
new file mode 100644
index 0000000..118c01b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/system_panel_airplane_default.png b/packages/SystemUI/res/drawable-hdpi/system_panel_airplane_default.png
new file mode 100644
index 0000000..e375ee9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/system_panel_airplane_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/system_panel_brightness_default.png b/packages/SystemUI/res/drawable-hdpi/system_panel_brightness_default.png
new file mode 100644
index 0000000..f62502b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/system_panel_brightness_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/system_panel_orientation_default.png b/packages/SystemUI/res/drawable-hdpi/system_panel_orientation_default.png
new file mode 100644
index 0000000..e887fb8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/system_panel_orientation_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/system_panel_orientation_locked.png b/packages/SystemUI/res/drawable-hdpi/system_panel_orientation_locked.png
new file mode 100644
index 0000000..58159d5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/system_panel_orientation_locked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/system_panel_sound_default.png b/packages/SystemUI/res/drawable-hdpi/system_panel_sound_default.png
new file mode 100644
index 0000000..6e857b5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/system_panel_sound_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/battery_0.png b/packages/SystemUI/res/drawable-mdpi/battery_0.png
new file mode 100644
index 0000000..b5d36cc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/battery_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/battery_100.png b/packages/SystemUI/res/drawable-mdpi/battery_100.png
new file mode 100644
index 0000000..75cc409
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/battery_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/battery_20.png b/packages/SystemUI/res/drawable-mdpi/battery_20.png
new file mode 100644
index 0000000..c0d0030
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/battery_20.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/battery_40.png b/packages/SystemUI/res/drawable-mdpi/battery_40.png
new file mode 100644
index 0000000..e301c08
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/battery_40.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/battery_60.png b/packages/SystemUI/res/drawable-mdpi/battery_60.png
new file mode 100644
index 0000000..0fde1fa
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/battery_60.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/battery_80.png b/packages/SystemUI/res/drawable-mdpi/battery_80.png
new file mode 100644
index 0000000..15c4e1c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/battery_80.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/button_frame_default.9.png b/packages/SystemUI/res/drawable-mdpi/button_frame_default.9.png
new file mode 100644
index 0000000..7ab1f26
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/button_frame_default.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/button_frame_pressed.9.png b/packages/SystemUI/res/drawable-mdpi/button_frame_pressed.9.png
new file mode 100644
index 0000000..08f7a4d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/button_frame_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/dots_empty.png b/packages/SystemUI/res/drawable-mdpi/dots_empty.png
new file mode 100644
index 0000000..22ada41
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/dots_empty.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/dots_full.png b/packages/SystemUI/res/drawable-mdpi/dots_full.png
new file mode 100644
index 0000000..2a346d6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/dots_full.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/notification_dragger.png b/packages/SystemUI/res/drawable-mdpi/notification_dragger.png
new file mode 100644
index 0000000..fad1f32
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/notification_dragger.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/signal_0.png b/packages/SystemUI/res/drawable-mdpi/signal_0.png
new file mode 100644
index 0000000..6533677
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/signal_100.png b/packages/SystemUI/res/drawable-mdpi/signal_100.png
new file mode 100644
index 0000000..e8976a2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/signal_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/signal_20.png b/packages/SystemUI/res/drawable-mdpi/signal_20.png
new file mode 100644
index 0000000..651e2a9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/signal_20.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/signal_40.png b/packages/SystemUI/res/drawable-mdpi/signal_40.png
new file mode 100644
index 0000000..6ba7906
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/signal_40.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/signal_60.png b/packages/SystemUI/res/drawable-mdpi/signal_60.png
new file mode 100644
index 0000000..6d2e812
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/signal_60.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/signal_80.png b/packages/SystemUI/res/drawable-mdpi/signal_80.png
new file mode 100644
index 0000000..a152623
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/signal_80.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_back_default.png b/packages/SystemUI/res/drawable-mdpi/status_bar_back_default.png
new file mode 100644
index 0000000..dd64746
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_back_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_back_pressed.png b/packages/SystemUI/res/drawable-mdpi/status_bar_back_pressed.png
new file mode 100644
index 0000000..66a3677
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_back_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_expand_default.png b/packages/SystemUI/res/drawable-mdpi/status_bar_expand_default.png
new file mode 100644
index 0000000..4d19717
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_expand_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_expand_pressed.png b/packages/SystemUI/res/drawable-mdpi/status_bar_expand_pressed.png
new file mode 100644
index 0000000..830cbd5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_expand_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_home_default.png b/packages/SystemUI/res/drawable-mdpi/status_bar_home_default.png
new file mode 100644
index 0000000..b129210
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_home_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_home_pressed.png b/packages/SystemUI/res/drawable-mdpi/status_bar_home_pressed.png
new file mode 100644
index 0000000..dcb2447
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_home_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_icon_tray.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_icon_tray.9.png
new file mode 100644
index 0000000..07d00cb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_icon_tray.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_menu_default.png b/packages/SystemUI/res/drawable-mdpi/status_bar_menu_default.png
new file mode 100644
index 0000000..bf3a755
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_menu_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_menu_pressed.png b/packages/SystemUI/res/drawable-mdpi/status_bar_menu_pressed.png
new file mode 100644
index 0000000..15e21d73
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_menu_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_veto_normal.png b/packages/SystemUI/res/drawable-mdpi/status_bar_veto_normal.png
new file mode 100644
index 0000000..f9a7cc2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_veto_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_veto_pressed.png b/packages/SystemUI/res/drawable-mdpi/status_bar_veto_pressed.png
new file mode 100644
index 0000000..4461ac8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_veto_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/system_panel_airplane_default.png b/packages/SystemUI/res/drawable-mdpi/system_panel_airplane_default.png
new file mode 100644
index 0000000..eb87532
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/system_panel_airplane_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/system_panel_brightness_default.png b/packages/SystemUI/res/drawable-mdpi/system_panel_brightness_default.png
new file mode 100644
index 0000000..3bfc83e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/system_panel_brightness_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/system_panel_orientation_default.png b/packages/SystemUI/res/drawable-mdpi/system_panel_orientation_default.png
new file mode 100644
index 0000000..0d8479c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/system_panel_orientation_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/system_panel_orientation_locked.png b/packages/SystemUI/res/drawable-mdpi/system_panel_orientation_locked.png
new file mode 100644
index 0000000..8f1d26c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/system_panel_orientation_locked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/system_panel_sound_default.png b/packages/SystemUI/res/drawable-mdpi/system_panel_sound_default.png
new file mode 100644
index 0000000..22636d6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/system_panel_sound_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/battery.xml b/packages/SystemUI/res/drawable/battery.xml
new file mode 100644
index 0000000..c2294d1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/battery.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/drawable/stat_sys_battery.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<level-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:maxLevel="1" android:drawable="@drawable/battery_0" />
+ <item android:maxLevel="5">
+ <animation-list android:oneshot="false">
+ <item android:drawable="@drawable/battery_0" android:duration="250" />
+ <item android:drawable="@drawable/battery_20" android:duration="250" />
+ </animation-list>
+ </item>
+ <item android:maxLevel="20" android:drawable="@drawable/battery_20" />
+ <item android:maxLevel="40" android:drawable="@drawable/battery_40" />
+ <item android:maxLevel="60" android:drawable="@drawable/battery_60" />
+ <item android:maxLevel="80" android:drawable="@drawable/battery_80" />
+ <item android:maxLevel="101" android:drawable="@drawable/battery_100" />
+</level-list>
+
diff --git a/packages/SystemUI/res/drawable/battery_charging.xml b/packages/SystemUI/res/drawable/battery_charging.xml
new file mode 100644
index 0000000..2fd0c6d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/battery_charging.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/drawable/stat_sys_battery.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<level-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:maxLevel="20">
+ <animation-list android:oneshot="false">
+ <item android:drawable="@drawable/battery_0" android:duration="1000" />
+ <item android:drawable="@drawable/battery_20" android:duration="1000" />
+ </animation-list>
+ </item>
+ <item android:maxLevel="40">
+ <animation-list android:oneshot="false">
+ <item android:drawable="@drawable/battery_20" android:duration="1000" />
+ <item android:drawable="@drawable/battery_40" android:duration="1000" />
+ </animation-list>
+ </item>
+ <item android:maxLevel="60">
+ <animation-list android:oneshot="false">
+ <item android:drawable="@drawable/battery_40" android:duration="1000" />
+ <item android:drawable="@drawable/battery_60" android:duration="1000" />
+ </animation-list>
+ </item>
+ <item android:maxLevel="80">
+ <animation-list android:oneshot="false">
+ <item android:drawable="@drawable/battery_60" android:duration="1000" />
+ <item android:drawable="@drawable/battery_80" android:duration="1000" />
+ </animation-list>
+ </item>
+ <item android:maxLevel="92">
+ <animation-list android:oneshot="false">
+ <item android:drawable="@drawable/battery_80" android:duration="1000" />
+ <item android:drawable="@drawable/battery_100" android:duration="1000" />
+ </animation-list>
+ </item>
+ <item android:maxLevel="101" android:drawable="@drawable/battery_100" />
+</level-list>
+
diff --git a/packages/SystemUI/res/drawable/button_frame.xml b/packages/SystemUI/res/drawable/button_frame.xml
new file mode 100644
index 0000000..5db39a5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/button_frame.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:drawable="@drawable/button_frame_pressed" />
+ <item android:drawable="@drawable/button_frame_default" />
+</selector>
+
diff --git a/packages/SystemUI/res/drawable/signal.xml b/packages/SystemUI/res/drawable/signal.xml
new file mode 100644
index 0000000..8b4f56b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/signal.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/drawable/stat_sys_battery.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<level-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:maxLevel="01" android:drawable="@drawable/signal_0" />
+ <item android:maxLevel="20" android:drawable="@drawable/signal_20" />
+ <item android:maxLevel="40" android:drawable="@drawable/signal_40" />
+ <item android:maxLevel="60" android:drawable="@drawable/signal_60" />
+ <item android:maxLevel="80" android:drawable="@drawable/signal_80" />
+ <item android:maxLevel="101" android:drawable="@drawable/signal_100" />
+
+</level-list>
+
diff --git a/packages/SystemUI/res/drawable/status_bar_back.xml b/packages/SystemUI/res/drawable/status_bar_back.xml
new file mode 100644
index 0000000..92bf147
--- /dev/null
+++ b/packages/SystemUI/res/drawable/status_bar_back.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:drawable="@drawable/status_bar_back_pressed" />
+ <item android:drawable="@drawable/status_bar_back_default" />
+</selector>
+
diff --git a/packages/SystemUI/res/drawable/status_bar_expand.xml b/packages/SystemUI/res/drawable/status_bar_expand.xml
new file mode 100644
index 0000000..f966920
--- /dev/null
+++ b/packages/SystemUI/res/drawable/status_bar_expand.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:drawable="@drawable/status_bar_expand_pressed" />
+ <item android:drawable="@drawable/status_bar_expand_default" />
+</selector>
+
diff --git a/packages/SystemUI/res/drawable/status_bar_home.xml b/packages/SystemUI/res/drawable/status_bar_home.xml
new file mode 100644
index 0000000..0011711
--- /dev/null
+++ b/packages/SystemUI/res/drawable/status_bar_home.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:drawable="@drawable/status_bar_home_pressed" />
+ <item android:drawable="@drawable/status_bar_home_default" />
+</selector>
+
diff --git a/packages/SystemUI/res/drawable/status_bar_menu.xml b/packages/SystemUI/res/drawable/status_bar_menu.xml
new file mode 100644
index 0000000..aa7286e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/status_bar_menu.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:drawable="@drawable/status_bar_menu_pressed" />
+ <item android:drawable="@drawable/status_bar_menu_default" />
+</selector>
+
diff --git a/packages/SystemUI/res/drawable/status_bar_veto.xml b/packages/SystemUI/res/drawable/status_bar_veto.xml
new file mode 100644
index 0000000..6e1b681
--- /dev/null
+++ b/packages/SystemUI/res/drawable/status_bar_veto.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:drawable="@drawable/status_bar_veto_pressed" />
+ <item android:drawable="@drawable/status_bar_veto_normal" />
+</selector>
+
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml
new file mode 100644
index 0000000..ffb1571
--- /dev/null
+++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2006, 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.
+*/
+-->
+
+<!-- android:background="@drawable/status_bar_closed_default_background" -->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
+ android:background="@drawable/status_bar_background"
+ android:focusable="true"
+ android:descendantFocusability="afterDescendants"
+ >
+
+ <com.android.systemui.statusbar.tablet.NotificationIconArea
+ android:id="@+id/notificationIcons"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentLeft="true"
+ android:paddingLeft="6dip"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:clickable="true"
+ android:onClick="notificationIconsClicked"
+ android:background="@drawable/status_bar_icon_tray"
+ >
+ <ImageView
+ class="com.android.systemui.statusbar.tablet.NotificationIconArea$MoreView"
+ android:id="@+id/expand"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/status_bar_expand"
+ android:onClick="notificationIconsClicked"
+ />
+ <view
+ class="com.android.systemui.statusbar.tablet.NotificationIconArea$IconLayout"
+ android:id="@+id/icons"
+ android:layout_width="wrap_content"
+ android:layout_height="@*android:dimen/status_bar_icon_size"
+ android:layout_marginLeft="8dip"
+ />
+ <view
+ class="com.android.systemui.statusbar.tablet.NotificationIconArea$DraggerView"
+ android:id="@+id/handle"
+ android:layout_width="24dip"
+ android:layout_height="match_parent"
+ android:layout_marginLeft="8dip"
+ />
+
+ </com.android.systemui.statusbar.tablet.NotificationIconArea>
+
+ <LinearLayout android:id="@+id/ticker"
+ android:layout_width="300dip"
+ android:layout_height="match_parent"
+ android:paddingLeft="6dip"
+ android:animationCache="false"
+ android:layout_alignLeft="@id/notificationIcons"
+ android:layout_alignTop="@id/notificationIcons"
+ android:orientation="horizontal"
+ android:visibility="gone"
+ >
+ <ImageView android:id="@+id/tickerIcon"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginRight="8dip"
+ />
+ <com.android.systemui.statusbar.TickerView android:id="@+id/tickerText"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:paddingTop="2dip"
+ android:paddingRight="10dip">
+ <TextView
+ android:textAppearance="@*android:style/TextAppearance.StatusBar.Ticker"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ />
+ <TextView
+ android:textAppearance="@*android:style/TextAppearance.StatusBar.Ticker"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ />
+ </com.android.systemui.statusbar.TickerView>
+ </LinearLayout>
+
+ <include layout="@layout/status_bar_center"
+ android:layout_width="100dip"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ />
+
+ <com.android.systemui.statusbar.KeyButtonView android:id="@+id/back"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_toLeftOf="@+id/menu"
+ android:paddingLeft="4dip"
+ android:paddingRight="4dip"
+ android:src="@drawable/status_bar_back"
+ systemui:keyCode="4"
+ />
+ <com.android.systemui.statusbar.KeyButtonView android:id="@+id/menu"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_toLeftOf="@+id/home"
+ android:src="@drawable/status_bar_menu"
+ android:paddingLeft="4dip"
+ android:paddingRight="4dip"
+ systemui:keyCode="82"
+ />
+ <com.android.systemui.statusbar.KeyButtonView android:id="@+id/home"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentRight="true"
+ android:paddingLeft="4dip"
+ android:paddingRight="4dip"
+ android:src="@drawable/status_bar_home"
+ systemui:keyCode="3"
+ />
+</RelativeLayout>
+
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_center.xml b/packages/SystemUI/res/layout-xlarge/status_bar_center.xml
new file mode 100644
index 0000000..775fea0
--- /dev/null
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_center.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Center of status bar: System info display, system info panel trigger -->
+<RelativeLayout android:id="@+id/systemInfo"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
+ android:layout_width="100dip"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:clickable="true"
+ android:onClick="systemInfoClicked"
+ >
+ <com.android.systemui.statusbar.Clock
+ style="@*android:style/TextAppearance.StatusBar.Icon"
+ android:id="@+id/clock"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:gravity="center"
+ android:textSize="16sp"
+ android:textStyle="bold"
+ android:padding="2dip"
+ />
+ <ImageView
+ android:id="@+id/battery"
+ android:layout_width="50dip"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_below="@id/clock"
+ android:src="@drawable/battery"
+ />
+ <ImageView
+ android:id="@+id/signal"
+ android:layout_width="50dip"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/clock"
+ android:src="@drawable/signal"
+ />
+</RelativeLayout>
+
+
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_latest_event.xml b/packages/SystemUI/res/layout-xlarge/status_bar_latest_event.xml
new file mode 100644
index 0000000..fa492d0
--- /dev/null
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_latest_event.xml
@@ -0,0 +1,36 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="65sp"
+ android:orientation="vertical"
+ android:background="@android:drawable/status_bar_item_background"
+ >
+
+ <ImageButton
+ android:id="@+id/veto"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ android:src="@drawable/status_bar_veto"
+ android:background="@null"
+ android:padding="2dip"
+ />
+
+ <com.android.systemui.statusbar.LatestItemView android:id="@+id/content"
+ android:layout_alignParentTop="true"
+ android:layout_toLeftOf="@id/veto"
+ android:layout_width="match_parent"
+ android:layout_height="64sp"
+ android:focusable="true"
+ android:clickable="true"
+ android:paddingRight="6sp"
+ />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1sp"
+ android:layout_alignParentBottom="true"
+ android:background="@android:drawable/divider_horizontal_dark"
+ />
+
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout-xlarge/sysbar_panel_notifications.xml b/packages/SystemUI/res/layout-xlarge/sysbar_panel_notifications.xml
new file mode 100644
index 0000000..3489eec
--- /dev/null
+++ b/packages/SystemUI/res/layout-xlarge/sysbar_panel_notifications.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2006, 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.
+*/
+-->
+
+<!-- android:background="@drawable/status_bar_closed_default_background" -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:background="#FF000000"
+ android:orientation="vertical"
+ >
+
+ <TextView android:id="@+id/clear_all_button"
+ style="?android:attr/textAppearance"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right|center_vertical"
+ android:layout_marginTop="2dip"
+ android:layout_marginBottom="1dip"
+ android:layout_marginRight="10dip"
+ android:padding="6dip"
+ android:textSize="14sp"
+ android:text="@string/status_bar_clear_all_button"
+ />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1sp"
+ android:background="@android:drawable/divider_horizontal_dark"
+ />
+
+ <ScrollView
+ android:id="@+id/notificationScroller"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ >
+ <LinearLayout
+ android:id="@+id/content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal|bottom"
+ android:animationCache="false"
+ android:orientation="vertical"
+ android:background="@drawable/status_bar_background"
+ android:clickable="true"
+ android:focusable="true"
+ android:descendantFocusability="afterDescendants"
+ >
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout-xlarge/sysbar_panel_system.xml b/packages/SystemUI/res/layout-xlarge/sysbar_panel_system.xml
new file mode 100644
index 0000000..273674f
--- /dev/null
+++ b/packages/SystemUI/res/layout-xlarge/sysbar_panel_system.xml
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 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.
+*/
+-->
+
+<com.android.systemui.statusbar.tablet.SystemPanel
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:background="#FF000000"
+ android:orientation="vertical"
+ >
+
+ <TextView android:id="@+id/settings_button"
+ style="?android:attr/textAppearance"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left|center_vertical"
+ android:layout_marginTop="2dip"
+ android:layout_marginBottom="1dip"
+ android:layout_marginRight="10dip"
+ android:padding="8dip"
+ android:textSize="20sp"
+ android:text="@string/system_panel_settings_button"
+ />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1sp"
+ android:background="@android:drawable/divider_horizontal_dark"
+ />
+
+ <LinearLayout
+ android:padding="8dip"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center"
+ >
+ <ImageButton android:id="@+id/brightness"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/system_panel_brightness_default"
+ android:background="@drawable/button_frame"
+ />
+ <ImageButton android:id="@+id/sound"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dip"
+ android:src="@drawable/system_panel_sound_default"
+ android:background="@drawable/button_frame"
+ />
+ <ImageButton android:id="@+id/orientation"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dip"
+ android:src="@drawable/system_panel_orientation_default"
+ android:background="@drawable/button_frame"
+ />
+ <ImageButton android:id="@+id/airplane"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dip"
+ android:src="@drawable/system_panel_airplane_default"
+ android:background="@drawable/button_frame"
+ />
+ </LinearLayout>
+
+ <RelativeLayout
+ android:padding="8dip"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ >
+ <RelativeLayout
+ android:layout_width="120dip"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ >
+ <ImageView android:id="@+id/battery_meter"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/battery"
+ />
+
+ <TextView android:id="@+id/battery_info"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_below="@id/battery_meter"
+ />
+ </RelativeLayout>
+
+ <com.android.systemui.statusbar.Clock
+ style="@*android:style/TextAppearance.StatusBar.Icon"
+ android:id="@+id/clock"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textSize="20sp"
+ android:textStyle="bold"
+ android:padding="2dip"
+ android:layout_centerHorizontal="true"
+ />
+
+ <TextView android:id="@+id/date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/clock"
+ />
+
+ <RelativeLayout
+ android:layout_width="120dip"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ >
+ <ImageView android:id="@+id/signal_meter"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/signal"
+ />
+
+ <TextView android:id="@+id/signal_info"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_below="@id/signal_meter"
+ />
+ </RelativeLayout>
+
+ </RelativeLayout>
+
+</com.android.systemui.statusbar.tablet.SystemPanel>
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 5fe8e79..2f1b36e 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -21,6 +21,7 @@
<!-- android:background="@drawable/status_bar_closed_default_background" -->
<com.android.systemui.statusbar.StatusBarView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
android:background="@drawable/status_bar_background"
android:orientation="vertical"
android:focusable="true"
diff --git a/packages/SystemUI/res/values-xlarge/colors.xml b/packages/SystemUI/res/values-xlarge/colors.xml
new file mode 100644
index 0000000..14161c3
--- /dev/null
+++ b/packages/SystemUI/res/values-xlarge/colors.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <drawable name="status_bar_background">#000000</drawable>
+</resources>
+
diff --git a/packages/SystemUI/res/values-xlarge/config.xml b/packages/SystemUI/res/values-xlarge/config.xml
new file mode 100644
index 0000000..4cf5d18d11
--- /dev/null
+++ b/packages/SystemUI/res/values-xlarge/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources>
+ <integer name="config_status_bar_position">1</integer>
+</resources>
+
diff --git a/packages/SystemUI/res/values-xlarge/strings.xml b/packages/SystemUI/res/values-xlarge/strings.xml
new file mode 100644
index 0000000..4aa4b47
--- /dev/null
+++ b/packages/SystemUI/res/values-xlarge/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- The text for the button in the notification window-shade that clears
+ all of the currently visible notifications. -->
+ <string name="status_bar_clear_all_button">Clear all</string>
+</resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
new file mode 100644
index 0000000..23bcf20
--- /dev/null
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <declare-styleable name="KeyButtonView">
+ <attr name="keyCode" format="integer" />
+ </declare-styleable>
+</resources>
+
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 8ea46e5..ac00c69 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -20,7 +20,16 @@
<!-- These resources are around just to allow their values to be customized
for different hardware and product builds. -->
<resources>
- <!-- Control whether status bar should distinguish HSPA data icon form UMTS data icon on devices -->
+
+ <!-- Control whether status bar should distinguish HSPA data icon form UMTS
+ data icon on devices -->
<bool name="config_hspa_data_distinguishable">false</bool>
+
+ <!-- The location of the status bar.
+ 0 - top
+ 1 - bottom
+ -->
+ <integer name="config_status_bar_position">0</integer>
+
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ba3a3d1..2df3b6d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -51,4 +51,7 @@
power usage activity to find out what drained the battery. -->
<string name="battery_low_why">Battery use</string>
+ <!-- Name of the button that links to the Settings app. [MAXCHARS=NONE] -->
+ <string name="system_panel_settings_button">Settings</string>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java
index f45caf5..0f6723e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java
@@ -23,7 +23,7 @@ import android.widget.LinearLayout;
public class CloseDragHandle extends LinearLayout {
- StatusBarService mService;
+ PhoneStatusBarService mService;
public CloseDragHandle(Context context, AttributeSet attrs) {
super(context, attrs);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index f9347b1..2c0af65 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -32,7 +32,7 @@ import com.android.internal.statusbar.StatusBarNotification;
* coalescing these calls so they don't stack up. For the calls
* are coalesced, note that they are all idempotent.
*/
-class CommandQueue extends IStatusBar.Stub {
+public class CommandQueue extends IStatusBar.Stub {
private static final String TAG = "StatusBar.CommandQueue";
private static final int MSG_MASK = 0xffff0000;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
index 3d85f27..a2d4b95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
@@ -27,7 +27,7 @@ import android.util.Slog;
public class ExpandedView extends LinearLayout {
- StatusBarService mService;
+ PhoneStatusBarService mService;
int mPrevHeight = -1;
public ExpandedView(Context context, AttributeSet attrs) {
@@ -53,7 +53,7 @@ public class ExpandedView extends LinearLayout {
//Slog.d(StatusBarService.TAG, "height changed old=" + mPrevHeight
// + " new=" + height);
mPrevHeight = height;
- mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE);
+ mService.updateExpandedViewPos(PhoneStatusBarService.EXPANDED_LEAVE_ALONE);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyButtonView.java
new file mode 100644
index 0000000..b0508b8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyButtonView.java
@@ -0,0 +1,122 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.AnimationDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.ServiceManager;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.IWindowManager;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.widget.ImageView;
+import android.widget.RemoteViews.RemoteView;
+
+import com.android.systemui.R;
+
+public class KeyButtonView extends ImageView {
+ IWindowManager mWindowManager;
+ long mDownTime;
+ boolean mSending;
+ int mCode;
+ int mRepeat;
+
+ public KeyButtonView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public KeyButtonView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs);
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyButtonView,
+ defStyle, 0);
+
+ mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, 0);
+ if (mCode == 0) {
+ Slog.w(StatusBarService.TAG, "KeyButtonView without key code id=0x"
+ + Integer.toHexString(getId()));
+ }
+
+ a.recycle();
+
+ mWindowManager = IWindowManager.Stub.asInterface(
+ ServiceManager.getService(Context.WINDOW_SERVICE));
+ }
+
+ public boolean onTouchEvent(MotionEvent ev) {
+ final int action = ev.getAction();
+ int x, y;
+
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ mDownTime = SystemClock.uptimeMillis();
+ mRepeat = 0;
+ mSending = true;
+ sendEvent(KeyEvent.ACTION_DOWN,
+ KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_SOFT_KEYBOARD, mDownTime);
+ setPressed(true);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (mSending) {
+ x = (int)ev.getX();
+ y = (int)ev.getY();
+ if (x < 0 || x >= getWidth() || y < 0 || y >= getHeight()) {
+ mSending = false;
+ sendEvent(KeyEvent.ACTION_UP,
+ KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_SOFT_KEYBOARD
+ | KeyEvent.FLAG_CANCELED);
+ setPressed(false);
+ }
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ if (mSending) {
+ mSending = false;
+ sendEvent(KeyEvent.ACTION_UP,
+ KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_SOFT_KEYBOARD);
+ setPressed(false);
+ }
+ break;
+ }
+
+ return true;
+ }
+
+ void sendEvent(int action, int flags) {
+ sendEvent(action, flags, SystemClock.uptimeMillis());
+ }
+
+ void sendEvent(int action, int flags, long when) {
+ final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, mRepeat,
+ 0, 0, 0, flags, InputDevice.SOURCE_KEYBOARD);
+ try {
+ Slog.d(StatusBarService.TAG, "injecting event " + ev);
+ mWindowManager.injectInputEventNoWait(ev);
+ } catch (RemoteException ex) {
+ // System process is dead
+ }
+ }
+}
+
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 7a82267..45abe93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -22,6 +22,7 @@ import android.view.View;
import com.android.internal.statusbar.StatusBarNotification;
+import java.util.Comparator;
import java.util.ArrayList;
/**
@@ -35,26 +36,47 @@ public class NotificationData {
public View row; // the outer expanded view
public View content; // takes the click events and sends the PendingIntent
public View expanded; // the inflated RemoteViews
+ public Entry() {}
+ public Entry(IBinder key, StatusBarNotification n, StatusBarIconView ic) {
+ this.key = key;
+ this.notification = n;
+ this.icon = ic;
+ }
}
private final ArrayList<Entry> mEntries = new ArrayList<Entry>();
+ private final Comparator<Entry> mEntryCmp = new Comparator<Entry>() {
+ public int compare(Entry a, Entry b) {
+ return (int)(a.notification.notification.when - b.notification.notification.when);
+ }
+ };
public int size() {
return mEntries.size();
}
- public Entry getEntryAt(int index) {
- return mEntries.get(index);
+ public Entry get(int i) {
+ return mEntries.get(i);
+ }
+
+ public Entry findByKey(IBinder key) {
+ for (Entry e : mEntries) {
+ if (e.key == key) {
+ return e;
+ }
+ }
+ return null;
}
- public int findEntry(IBinder key) {
- final int N = mEntries.size();
- for (int i=0; i<N; i++) {
- Entry entry = mEntries.get(i);
- if (entry.key == key) {
- return i;
+ public int add(Entry entry) {
+ int i;
+ int N = mEntries.size();
+ for (i=0; i<N; i++) {
+ if (mEntryCmp.compare(mEntries.get(i), entry) > 0) {
+ break;
}
}
- return -1;
+ mEntries.add(i, entry);
+ return i;
}
public int add(IBinder key, StatusBarNotification notification, View row, View content,
@@ -66,42 +88,23 @@ public class NotificationData {
entry.content = content;
entry.expanded = expanded;
entry.icon = icon;
- final int index = chooseIndex(notification.notification.when);
- mEntries.add(index, entry);
- return index;
+ return add(entry);
}
public Entry remove(IBinder key) {
- final int N = mEntries.size();
- for (int i=0; i<N; i++) {
- Entry entry = mEntries.get(i);
- if (entry.key == key) {
- mEntries.remove(i);
- return entry;
- }
- }
- return null;
- }
-
- private int chooseIndex(final long when) {
- final int N = mEntries.size();
- for (int i=0; i<N; i++) {
- Entry entry = mEntries.get(i);
- if (entry.notification.notification.when > when) {
- return i;
- }
+ Entry e = findByKey(key);
+ if (e != null) {
+ mEntries.remove(e);
}
- return N;
+ return e;
}
/**
* Return whether there are any visible items (i.e. items without an error).
*/
public boolean hasVisibleItems() {
- final int N = mEntries.size();
- for (int i=0; i<N; i++) {
- Entry entry = mEntries.get(i);
- if (entry.expanded != null) { // the view successfully inflated
+ for (Entry e : mEntries) {
+ if (e.expanded != null) { // the view successfully inflated
return true;
}
}
@@ -112,11 +115,9 @@ public class NotificationData {
* Return whether there are any clearable items (that aren't errors).
*/
public boolean hasClearableItems() {
- final int N = mEntries.size();
- for (int i=0; i<N; i++) {
- Entry entry = mEntries.get(i);
- if (entry.expanded != null) { // the view successfully inflated
- if ((entry.notification.notification.flags & Notification.FLAG_NO_CLEAR) == 0) {
+ for (Entry e : mEntries) {
+ if (e.expanded != null) { // the view successfully inflated
+ if ((e.notification.notification.flags & Notification.FLAG_NO_CLEAR) == 0) {
return true;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
new file mode 100644
index 0000000..91b583b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
@@ -0,0 +1,1551 @@
+/*
+ * 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;
+
+import android.app.Service;
+import android.app.ActivityManagerNative;
+import android.app.Dialog;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.util.Log;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RemoteViews;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.FrameLayout;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Set;
+
+import com.android.internal.statusbar.IStatusBar;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.statusbar.StatusBarNotification;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.StatusBarPolicy;
+
+
+
+public class PhoneStatusBarService extends StatusBarService {
+ static final String TAG = "PhoneStatusBarService";
+ static final boolean SPEW = false;
+
+ public static final String ACTION_STATUSBAR_START
+ = "com.android.internal.policy.statusbar.START";
+
+ static final int EXPANDED_LEAVE_ALONE = -10000;
+ static final int EXPANDED_FULL_OPEN = -10001;
+
+ private static final int MSG_ANIMATE = 1000;
+ private static final int MSG_ANIMATE_REVEAL = 1001;
+ private static final int MSG_SHOW_INTRUDER = 1002;
+ private static final int MSG_HIDE_INTRUDER = 1003;
+
+ // will likely move to a resource or other tunable param at some point
+ private static final int INTRUDER_ALERT_DECAY_MS = 10000;
+
+ StatusBarPolicy mIconPolicy;
+
+ int mIconSize;
+ Display mDisplay;
+
+ StatusBarView mStatusBarView;
+ int mPixelFormat;
+ H mHandler = new H();
+ Object mQueueLock = new Object();
+
+ // icons
+ LinearLayout mIcons;
+ IconMerger mNotificationIcons;
+ LinearLayout mStatusIcons;
+
+ // expanded notifications
+ Dialog mExpandedDialog;
+ ExpandedView mExpandedView;
+ WindowManager.LayoutParams mExpandedParams;
+ ScrollView mScrollView;
+ View mNotificationLinearLayout;
+ View mExpandedContents;
+ // top bar
+ TextView mNoNotificationsTitle;
+ TextView mClearButton;
+ // drag bar
+ CloseDragHandle mCloseView;
+ // ongoing
+ NotificationData mOngoing = new NotificationData();
+ TextView mOngoingTitle;
+ LinearLayout mOngoingItems;
+ // latest
+ NotificationData mLatest = new NotificationData();
+ TextView mLatestTitle;
+ LinearLayout mLatestItems;
+ // position
+ int[] mPositionTmp = new int[2];
+ boolean mExpanded;
+ boolean mExpandedVisible;
+
+ // the date view
+ DateView mDateView;
+
+ // for immersive activities
+ private View mIntruderAlertView;
+
+ // the tracker view
+ TrackingView mTrackingView;
+ WindowManager.LayoutParams mTrackingParams;
+ int mTrackingPosition; // the position of the top of the tracking view.
+ private boolean mPanelSlightlyVisible;
+
+ // ticker
+ private Ticker mTicker;
+ private View mTickerView;
+ private boolean mTicking;
+
+ // Tracking finger for opening/closing.
+ int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
+ boolean mTracking;
+ VelocityTracker mVelocityTracker;
+
+ static final int ANIM_FRAME_DURATION = (1000/60);
+
+ boolean mAnimating;
+ long mCurAnimationTime;
+ float mDisplayHeight;
+ float mAnimY;
+ float mAnimVel;
+ float mAnimAccel;
+ long mAnimLastTime;
+ boolean mAnimatingReveal = false;
+ int mViewDelta;
+ int[] mAbsPos = new int[2];
+
+ // for disabling the status bar
+ int mDisabled = 0;
+
+ private class ExpandedDialog extends Dialog {
+ ExpandedDialog(Context context) {
+ super(context, com.android.internal.R.style.Theme_Light_NoTitleBar);
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+ switch (event.getKeyCode()) {
+ case KeyEvent.KEYCODE_BACK:
+ if (!down) {
+ animateCollapse();
+ }
+ return true;
+ }
+ return super.dispatchKeyEvent(event);
+ }
+ }
+
+ @Override
+ public void onCreate() {
+ mDisplay = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+
+ super.onCreate();
+
+ addIntruderView();
+
+ // Lastly, call to the icon policy to install/update all the icons.
+ mIconPolicy = new StatusBarPolicy(this);
+ }
+
+ @Override
+ public void onDestroy() {
+ // we're never destroyed
+ }
+
+ // ================================================================================
+ // Constructing the view
+ // ================================================================================
+ protected View makeStatusBarView() {
+ final Context context = this;
+
+ Resources res = context.getResources();
+
+ mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
+
+ ExpandedView expanded = (ExpandedView)View.inflate(context,
+ R.layout.status_bar_expanded, null);
+ expanded.mService = this;
+
+ mIntruderAlertView = View.inflate(context, R.layout.intruder_alert, null);
+ mIntruderAlertView.setVisibility(View.GONE);
+ mIntruderAlertView.setClickable(true);
+
+ StatusBarView sb = (StatusBarView)View.inflate(context, R.layout.status_bar, null);
+ sb.mService = this;
+
+ // figure out which pixel-format to use for the status bar.
+ mPixelFormat = PixelFormat.TRANSLUCENT;
+ Drawable bg = sb.getBackground();
+ if (bg != null) {
+ mPixelFormat = bg.getOpacity();
+ }
+
+ mStatusBarView = sb;
+ mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons);
+ mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons);
+ mIcons = (LinearLayout)sb.findViewById(R.id.icons);
+ mTickerView = sb.findViewById(R.id.ticker);
+ mDateView = (DateView)sb.findViewById(R.id.date);
+
+ mExpandedDialog = new ExpandedDialog(context);
+ mExpandedView = expanded;
+ mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout);
+ mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle);
+ mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems);
+ mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle);
+ mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems);
+ mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle);
+ mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button);
+ mClearButton.setOnClickListener(mClearButtonListener);
+ mScrollView = (ScrollView)expanded.findViewById(R.id.scroll);
+ mNotificationLinearLayout = expanded.findViewById(R.id.notificationLinearLayout);
+
+ mOngoingTitle.setVisibility(View.GONE);
+ mLatestTitle.setVisibility(View.GONE);
+
+ mTicker = new MyTicker(context, sb);
+
+ TickerView tickerView = (TickerView)sb.findViewById(R.id.tickerText);
+ tickerView.mTicker = mTicker;
+
+ mTrackingView = (TrackingView)View.inflate(context, R.layout.status_bar_tracking, null);
+ mTrackingView.mService = this;
+ mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close);
+ mCloseView.mService = this;
+
+ mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
+
+ // the more notifications icon
+ StatusBarIconView moreView = new StatusBarIconView(this, "more");
+ moreView.set(new StatusBarIcon(null, R.drawable.stat_notify_more, 0));
+ mNotificationIcons.addMoreView(moreView,
+ new LinearLayout.LayoutParams(mIconSize, mIconSize));
+
+ // set the inital view visibility
+ setAreThereNotifications();
+ mDateView.setVisibility(View.INVISIBLE);
+
+ // receive broadcasts
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+ filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ context.registerReceiver(mBroadcastReceiver, filter);
+
+ return sb;
+ }
+
+ protected int getStatusBarGravity() {
+ return Gravity.TOP | Gravity.FILL_HORIZONTAL;
+ }
+
+ private void addIntruderView() {
+ final Resources res = getResources();
+ final int height= res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+ PixelFormat.TRANSLUCENT);
+ lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+ lp.y += height * 1.5; // FIXME
+ lp.setTitle("IntruderAlert");
+ lp.windowAnimations = com.android.internal.R.style.Animation_StatusBar_IntruderAlert;
+
+ WindowManagerImpl.getDefault().addView(mIntruderAlertView, lp);
+ }
+
+ public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
+ if (SPEW) Slog.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
+ + " icon=" + icon);
+ StatusBarIconView view = new StatusBarIconView(this, slot);
+ view.set(icon);
+ mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconSize, mIconSize));
+ }
+
+ public void updateIcon(String slot, int index, int viewIndex,
+ StatusBarIcon old, StatusBarIcon icon) {
+ if (SPEW) Slog.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
+ + " old=" + old + " icon=" + icon);
+ StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex);
+ view.set(icon);
+ }
+
+ public void removeIcon(String slot, int index, int viewIndex) {
+ if (SPEW) Slog.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex);
+ mStatusIcons.removeViewAt(viewIndex);
+ }
+
+ public void addNotification(IBinder key, StatusBarNotification notification) {
+ StatusBarIconView iconView = addNotificationViews(key, notification);
+ if (iconView == null) return;
+
+ boolean immersive = false;
+ try {
+ immersive = ActivityManagerNative.getDefault().isTopActivityImmersive();
+ Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));
+ } catch (RemoteException ex) {
+ }
+ if (immersive) {
+ if ((notification.notification.flags & Notification.FLAG_HIGH_PRIORITY) != 0) {
+ Slog.d(TAG, "Presenting high-priority notification in immersive activity");
+ // special new transient ticker mode
+ // 1. Populate mIntruderAlertView
+
+ ImageView alertIcon = (ImageView) mIntruderAlertView.findViewById(R.id.alertIcon);
+ TextView alertText = (TextView) mIntruderAlertView.findViewById(R.id.alertText);
+ alertIcon.setImageDrawable(StatusBarIconView.getIcon(
+ alertIcon.getContext(),
+ iconView.getStatusBarIcon()));
+ alertText.setText(notification.notification.tickerText);
+
+ View button = mIntruderAlertView.findViewById(R.id.intruder_alert_content);
+ button.setOnClickListener(
+ new Launcher(notification.notification.contentIntent,
+ notification.pkg, notification.tag, notification.id));
+
+ // 2. Animate mIntruderAlertView in
+ mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER);
+
+ // 3. Set alarm to age the notification off (TODO)
+ mHandler.removeMessages(MSG_HIDE_INTRUDER);
+ mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS);
+ }
+ } else if (notification.notification.fullScreenIntent != null) {
+ // not immersive & a full-screen alert should be shown
+ Slog.d(TAG, "Notification has fullScreenIntent and activity is not immersive;"
+ + " sending fullScreenIntent");
+ try {
+ notification.notification.fullScreenIntent.send();
+ } catch (PendingIntent.CanceledException e) {
+ }
+ } else {
+ // usual case: status bar visible & not immersive
+
+ // show the ticker
+ tick(notification);
+ }
+
+ // Recalculate the position of the sliding windows and the titles.
+ setAreThereNotifications();
+ updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+ }
+
+ public void updateNotification(IBinder key, StatusBarNotification notification) {
+ Slog.d(TAG, "updateNotification key=" + key + " notification=" + notification);
+
+ NotificationData oldList;
+ NotificationData.Entry oldEntry = mOngoing.findByKey(key);
+ if (oldEntry != null) {
+ oldList = mOngoing;
+ } else {
+ oldEntry = mLatest.findByKey(key);
+ if (oldEntry == null) {
+ Slog.w(TAG, "updateNotification for unknown key: " + key);
+ return;
+ }
+ oldList = mLatest;
+ }
+ final StatusBarNotification oldNotification = oldEntry.notification;
+ final RemoteViews oldContentView = oldNotification.notification.contentView;
+
+ final RemoteViews contentView = notification.notification.contentView;
+
+ if (false) {
+ Slog.d(TAG, "old notification: when=" + oldNotification.notification.when
+ + " ongoing=" + oldNotification.isOngoing()
+ + " expanded=" + oldEntry.expanded
+ + " contentView=" + oldContentView);
+ Slog.d(TAG, "new notification: when=" + notification.notification.when
+ + " ongoing=" + oldNotification.isOngoing()
+ + " contentView=" + contentView);
+ }
+
+ // Can we just reapply the RemoteViews in place? If when didn't change, the order
+ // didn't change.
+ if (notification.notification.when == oldNotification.notification.when
+ && notification.isOngoing() == oldNotification.isOngoing()
+ && oldEntry.expanded != null
+ && contentView != null && oldContentView != null
+ && contentView.getPackage() != null
+ && oldContentView.getPackage() != null
+ && oldContentView.getPackage().equals(contentView.getPackage())
+ && oldContentView.getLayoutId() == contentView.getLayoutId()) {
+ if (SPEW) Slog.d(TAG, "reusing notification");
+ oldEntry.notification = notification;
+ try {
+ // Reapply the RemoteViews
+ contentView.reapply(this, oldEntry.content);
+ // update the contentIntent
+ final PendingIntent contentIntent = notification.notification.contentIntent;
+ if (contentIntent != null) {
+ oldEntry.content.setOnClickListener(new Launcher(contentIntent,
+ notification.pkg, notification.tag, notification.id));
+ }
+ // Update the icon.
+ final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
+ notification.notification.icon, notification.notification.iconLevel,
+ notification.notification.number);
+ if (!oldEntry.icon.set(ic)) {
+ handleNotificationError(key, notification, "Couldn't update icon: " + ic);
+ return;
+ }
+ }
+ catch (RuntimeException e) {
+ // It failed to add cleanly. Log, and remove the view from the panel.
+ Slog.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
+ removeNotificationViews(key);
+ addNotificationViews(key, notification);
+ }
+ } else {
+ if (SPEW) Slog.d(TAG, "not reusing notification");
+ removeNotificationViews(key);
+ addNotificationViews(key, notification);
+ }
+
+ // Restart the ticker if it's still running
+ tick(notification);
+
+ // Recalculate the position of the sliding windows and the titles.
+ setAreThereNotifications();
+ updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+ }
+
+ public void removeNotification(IBinder key) {
+ if (SPEW) Slog.d(TAG, "removeNotification key=" + key);
+ StatusBarNotification old = removeNotificationViews(key);
+
+ if (old != null) {
+ // Cancel the ticker if it's still running
+ mTicker.removeEntry(old);
+
+ // Recalculate the position of the sliding windows and the titles.
+ setAreThereNotifications();
+ updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+ }
+ }
+
+ private int chooseIconIndex(boolean isOngoing, int viewIndex) {
+ final int latestSize = mLatest.size();
+ if (isOngoing) {
+ return latestSize + (mOngoing.size() - viewIndex);
+ } else {
+ return latestSize - viewIndex;
+ }
+ }
+
+ View[] makeNotificationView(StatusBarNotification notification, ViewGroup parent) {
+ Notification n = notification.notification;
+ RemoteViews remoteViews = n.contentView;
+ if (remoteViews == null) {
+ return null;
+ }
+
+ // create the row view
+ LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ View row = inflater.inflate(R.layout.status_bar_latest_event, parent, false);
+
+ // bind the click event to the content area
+ ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
+ content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+ content.setOnFocusChangeListener(mFocusChangeListener);
+ PendingIntent contentIntent = n.contentIntent;
+ if (contentIntent != null) {
+ content.setOnClickListener(new Launcher(contentIntent, notification.pkg,
+ notification.tag, notification.id));
+ }
+
+ View expanded = null;
+ Exception exception = null;
+ try {
+ expanded = remoteViews.apply(this, content);
+ }
+ catch (RuntimeException e) {
+ exception = e;
+ }
+ if (expanded == null) {
+ String ident = notification.pkg + "/0x" + Integer.toHexString(notification.id);
+ Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
+ return null;
+ } else {
+ content.addView(expanded);
+ row.setDrawingCacheEnabled(true);
+ }
+
+ return new View[] { row, content, expanded };
+ }
+
+ StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) {
+ NotificationData list;
+ ViewGroup parent;
+ final boolean isOngoing = notification.isOngoing();
+ if (isOngoing) {
+ list = mOngoing;
+ parent = mOngoingItems;
+ } else {
+ list = mLatest;
+ parent = mLatestItems;
+ }
+ // Construct the expanded view.
+ final View[] views = makeNotificationView(notification, parent);
+ if (views == null) {
+ handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
+ + notification);
+ return null;
+ }
+ final View row = views[0];
+ final View content = views[1];
+ final View expanded = views[2];
+ // Construct the icon.
+ final StatusBarIconView iconView = new StatusBarIconView(this,
+ notification.pkg + "/0x" + Integer.toHexString(notification.id));
+ final StatusBarIcon ic = new StatusBarIcon(notification.pkg, notification.notification.icon,
+ notification.notification.iconLevel, notification.notification.number);
+ if (!iconView.set(ic)) {
+ handleNotificationError(key, notification, "Coulding create icon: " + ic);
+ return null;
+ }
+ // Add the expanded view.
+ final int viewIndex = list.add(key, notification, row, content, expanded, iconView);
+ parent.addView(row, viewIndex);
+ // Add the icon.
+ final int iconIndex = chooseIconIndex(isOngoing, viewIndex);
+ mNotificationIcons.addView(iconView, iconIndex,
+ new LinearLayout.LayoutParams(mIconSize, mIconSize));
+ return iconView;
+ }
+
+ StatusBarNotification removeNotificationViews(IBinder key) {
+ NotificationData.Entry entry = mOngoing.remove(key);
+ if (entry == null) {
+ entry = mLatest.remove(key);
+ if (entry == null) {
+ Slog.w(TAG, "removeNotification for unknown key: " + key);
+ return null;
+ }
+ }
+ // Remove the expanded view.
+ ((ViewGroup)entry.row.getParent()).removeView(entry.row);
+ // Remove the icon.
+ ((ViewGroup)entry.icon.getParent()).removeView(entry.icon);
+
+ return entry.notification;
+ }
+
+ private void setAreThereNotifications() {
+ boolean ongoing = mOngoing.hasVisibleItems();
+ boolean latest = mLatest.hasVisibleItems();
+
+ // (no ongoing notifications are clearable)
+ if (mLatest.hasClearableItems()) {
+ mClearButton.setVisibility(View.VISIBLE);
+ } else {
+ mClearButton.setVisibility(View.INVISIBLE);
+ }
+
+ mOngoingTitle.setVisibility(ongoing ? View.VISIBLE : View.GONE);
+ mLatestTitle.setVisibility(latest ? View.VISIBLE : View.GONE);
+
+ if (ongoing || latest) {
+ mNoNotificationsTitle.setVisibility(View.GONE);
+ } else {
+ mNoNotificationsTitle.setVisibility(View.VISIBLE);
+ }
+ }
+
+
+ /**
+ * State is one or more of the DISABLE constants from StatusBarManager.
+ */
+ public void disable(int state) {
+ final int old = mDisabled;
+ final int diff = state ^ old;
+ mDisabled = state;
+
+ if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
+ if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
+ Slog.d(TAG, "DISABLE_EXPAND: yes");
+ animateCollapse();
+ }
+ }
+ if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+ if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+ Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
+ if (mTicking) {
+ mTicker.halt();
+ } else {
+ setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
+ }
+ } else {
+ Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
+ if (!mExpandedVisible) {
+ setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
+ }
+ }
+ } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+ if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+ Slog.d(TAG, "DISABLE_NOTIFICATION_TICKER: yes");
+ mTicker.halt();
+ }
+ }
+ }
+
+ /**
+ * All changes to the status bar and notifications funnel through here and are batched.
+ */
+ private class H extends Handler {
+ public void handleMessage(Message m) {
+ switch (m.what) {
+ case MSG_ANIMATE:
+ doAnimation();
+ break;
+ case MSG_ANIMATE_REVEAL:
+ doRevealAnimation();
+ break;
+ case MSG_SHOW_INTRUDER:
+ setIntruderAlertVisibility(true);
+ break;
+ case MSG_HIDE_INTRUDER:
+ setIntruderAlertVisibility(false);
+ break;
+ }
+ }
+ }
+
+ View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() {
+ public void onFocusChange(View v, boolean hasFocus) {
+ // Because 'v' is a ViewGroup, all its children will be (un)selected
+ // too, which allows marqueeing to work.
+ v.setSelected(hasFocus);
+ }
+ };
+
+ private void makeExpandedVisible() {
+ if (SPEW) Slog.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
+ if (mExpandedVisible) {
+ return;
+ }
+ mExpandedVisible = true;
+ visibilityChanged(true);
+
+ updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+ mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+ mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+ mExpandedView.requestFocus(View.FOCUS_FORWARD);
+ mTrackingView.setVisibility(View.VISIBLE);
+
+ if (!mTicking) {
+ setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
+ }
+ }
+
+ public void animateExpand() {
+ if (SPEW) Slog.d(TAG, "Animate expand: expanded=" + mExpanded);
+ if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
+ return ;
+ }
+ if (mExpanded) {
+ return;
+ }
+
+ prepareTracking(0, true);
+ performFling(0, 2000.0f, true);
+ }
+
+ public void animateCollapse() {
+ if (SPEW) {
+ Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
+ + " mExpandedVisible=" + mExpandedVisible
+ + " mExpanded=" + mExpanded
+ + " mAnimating=" + mAnimating
+ + " mAnimY=" + mAnimY
+ + " mAnimVel=" + mAnimVel);
+ }
+
+ if (!mExpandedVisible) {
+ return;
+ }
+
+ int y;
+ if (mAnimating) {
+ y = (int)mAnimY;
+ } else {
+ y = mDisplay.getHeight()-1;
+ }
+ // Let the fling think that we're open so it goes in the right direction
+ // and doesn't try to re-open the windowshade.
+ mExpanded = true;
+ prepareTracking(y, false);
+ performFling(y, -2000.0f, true);
+ }
+
+ void performExpand() {
+ if (SPEW) Slog.d(TAG, "performExpand: mExpanded=" + mExpanded);
+ if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
+ return ;
+ }
+ if (mExpanded) {
+ return;
+ }
+
+ mExpanded = true;
+ makeExpandedVisible();
+ updateExpandedViewPos(EXPANDED_FULL_OPEN);
+
+ if (false) postStartTracing();
+ }
+
+ void performCollapse() {
+ if (SPEW) Slog.d(TAG, "performCollapse: mExpanded=" + mExpanded
+ + " mExpandedVisible=" + mExpandedVisible);
+
+ if (!mExpandedVisible) {
+ return;
+ }
+ mExpandedVisible = false;
+ visibilityChanged(false);
+ mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+ mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+ mTrackingView.setVisibility(View.GONE);
+
+ if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
+ setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
+ }
+ setDateViewVisibility(false, com.android.internal.R.anim.fade_out);
+
+ if (!mExpanded) {
+ return;
+ }
+ mExpanded = false;
+ }
+
+ void doAnimation() {
+ if (mAnimating) {
+ if (SPEW) Slog.d(TAG, "doAnimation");
+ if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
+ incrementAnim();
+ if (SPEW) Slog.d(TAG, "doAnimation after mAnimY=" + mAnimY);
+ if (mAnimY >= mDisplay.getHeight()-1) {
+ if (SPEW) Slog.d(TAG, "Animation completed to expanded state.");
+ mAnimating = false;
+ updateExpandedViewPos(EXPANDED_FULL_OPEN);
+ performExpand();
+ }
+ else if (mAnimY < mStatusBarView.getHeight()) {
+ if (SPEW) Slog.d(TAG, "Animation completed to collapsed state.");
+ mAnimating = false;
+ updateExpandedViewPos(0);
+ performCollapse();
+ }
+ else {
+ updateExpandedViewPos((int)mAnimY);
+ mCurAnimationTime += ANIM_FRAME_DURATION;
+ mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
+ }
+ }
+ }
+
+ void stopTracking() {
+ mTracking = false;
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+
+ void incrementAnim() {
+ long now = SystemClock.uptimeMillis();
+ float t = ((float)(now - mAnimLastTime)) / 1000; // ms -> s
+ final float y = mAnimY;
+ final float v = mAnimVel; // px/s
+ final float a = mAnimAccel; // px/s/s
+ mAnimY = y + (v*t) + (0.5f*a*t*t); // px
+ mAnimVel = v + (a*t); // px/s
+ mAnimLastTime = now; // ms
+ //Slog.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY
+ // + " mAnimAccel=" + mAnimAccel);
+ }
+
+ void doRevealAnimation() {
+ final int h = mCloseView.getHeight() + mStatusBarView.getHeight();
+ if (mAnimatingReveal && mAnimating && mAnimY < h) {
+ incrementAnim();
+ if (mAnimY >= h) {
+ mAnimY = h;
+ updateExpandedViewPos((int)mAnimY);
+ } else {
+ updateExpandedViewPos((int)mAnimY);
+ mCurAnimationTime += ANIM_FRAME_DURATION;
+ mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
+ mCurAnimationTime);
+ }
+ }
+ }
+
+ void prepareTracking(int y, boolean opening) {
+ mTracking = true;
+ mVelocityTracker = VelocityTracker.obtain();
+ if (opening) {
+ mAnimAccel = 2000.0f;
+ mAnimVel = 200;
+ mAnimY = mStatusBarView.getHeight();
+ updateExpandedViewPos((int)mAnimY);
+ mAnimating = true;
+ mAnimatingReveal = true;
+ mHandler.removeMessages(MSG_ANIMATE);
+ mHandler.removeMessages(MSG_ANIMATE_REVEAL);
+ long now = SystemClock.uptimeMillis();
+ mAnimLastTime = now;
+ mCurAnimationTime = now + ANIM_FRAME_DURATION;
+ mAnimating = true;
+ mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
+ mCurAnimationTime);
+ makeExpandedVisible();
+ } else {
+ // it's open, close it?
+ if (mAnimating) {
+ mAnimating = false;
+ mHandler.removeMessages(MSG_ANIMATE);
+ }
+ updateExpandedViewPos(y + mViewDelta);
+ }
+ }
+
+ void performFling(int y, float vel, boolean always) {
+ mAnimatingReveal = false;
+ mDisplayHeight = mDisplay.getHeight();
+
+ mAnimY = y;
+ mAnimVel = vel;
+
+ //Slog.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel);
+
+ if (mExpanded) {
+ if (!always && (
+ vel > 200.0f
+ || (y > (mDisplayHeight-25) && vel > -200.0f))) {
+ // We are expanded, but they didn't move sufficiently to cause
+ // us to retract. Animate back to the expanded position.
+ mAnimAccel = 2000.0f;
+ if (vel < 0) {
+ mAnimVel = 0;
+ }
+ }
+ else {
+ // We are expanded and are now going to animate away.
+ mAnimAccel = -2000.0f;
+ if (vel > 0) {
+ mAnimVel = 0;
+ }
+ }
+ } else {
+ if (always || (
+ vel > 200.0f
+ || (y > (mDisplayHeight/2) && vel > -200.0f))) {
+ // We are collapsed, and they moved enough to allow us to
+ // expand. Animate in the notifications.
+ mAnimAccel = 2000.0f;
+ if (vel < 0) {
+ mAnimVel = 0;
+ }
+ }
+ else {
+ // We are collapsed, but they didn't move sufficiently to cause
+ // us to retract. Animate back to the collapsed position.
+ mAnimAccel = -2000.0f;
+ if (vel > 0) {
+ mAnimVel = 0;
+ }
+ }
+ }
+ //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel
+ // + " mAnimAccel=" + mAnimAccel);
+
+ long now = SystemClock.uptimeMillis();
+ mAnimLastTime = now;
+ mCurAnimationTime = now + ANIM_FRAME_DURATION;
+ mAnimating = true;
+ mHandler.removeMessages(MSG_ANIMATE);
+ mHandler.removeMessages(MSG_ANIMATE_REVEAL);
+ mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
+ stopTracking();
+ }
+
+ boolean interceptTouchEvent(MotionEvent event) {
+ if (SPEW) {
+ Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
+ + mDisabled);
+ }
+
+ if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
+ return false;
+ }
+
+ final int statusBarSize = mStatusBarView.getHeight();
+ final int hitSize = statusBarSize*2;
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ final int y = (int)event.getRawY();
+
+ if (!mExpanded) {
+ mViewDelta = statusBarSize - y;
+ } else {
+ mTrackingView.getLocationOnScreen(mAbsPos);
+ mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y;
+ }
+ if ((!mExpanded && y < hitSize) ||
+ (mExpanded && y > (mDisplay.getHeight()-hitSize))) {
+
+ // We drop events at the edge of the screen to make the windowshade come
+ // down by accident less, especially when pushing open a device with a keyboard
+ // that rotates (like g1 and droid)
+ int x = (int)event.getRawX();
+ final int edgeBorder = mEdgeBorder;
+ if (x >= edgeBorder && x < mDisplay.getWidth() - edgeBorder) {
+ prepareTracking(y, !mExpanded);// opening if we're not already fully visible
+ mVelocityTracker.addMovement(event);
+ }
+ }
+ } else if (mTracking) {
+ mVelocityTracker.addMovement(event);
+ final int minY = statusBarSize + mCloseView.getHeight();
+ if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ int y = (int)event.getRawY();
+ if (mAnimatingReveal && y < minY) {
+ // nothing
+ } else {
+ mAnimatingReveal = false;
+ updateExpandedViewPos(y + mViewDelta);
+ }
+ } else if (event.getAction() == MotionEvent.ACTION_UP) {
+ mVelocityTracker.computeCurrentVelocity(1000);
+
+ float yVel = mVelocityTracker.getYVelocity();
+ boolean negative = yVel < 0;
+
+ float xVel = mVelocityTracker.getXVelocity();
+ if (xVel < 0) {
+ xVel = -xVel;
+ }
+ if (xVel > 150.0f) {
+ xVel = 150.0f; // limit how much we care about the x axis
+ }
+
+ float vel = (float)Math.hypot(yVel, xVel);
+ if (negative) {
+ vel = -vel;
+ }
+
+ performFling((int)event.getRawY(), vel, false);
+ }
+
+ }
+ return false;
+ }
+
+ private class Launcher implements View.OnClickListener {
+ private PendingIntent mIntent;
+ private String mPkg;
+ private String mTag;
+ private int mId;
+
+ Launcher(PendingIntent intent, String pkg, String tag, int id) {
+ mIntent = intent;
+ mPkg = pkg;
+ mTag = tag;
+ mId = id;
+ }
+
+ public void onClick(View v) {
+ try {
+ // The intent we are sending is for the application, which
+ // won't have permission to immediately start an activity after
+ // the user switches to home. We know it is safe to do at this
+ // point, so make sure new activity switches are now allowed.
+ ActivityManagerNative.getDefault().resumeAppSwitches();
+ } catch (RemoteException e) {
+ }
+
+ if (mIntent != null) {
+ int[] pos = new int[2];
+ v.getLocationOnScreen(pos);
+ Intent overlay = new Intent();
+ overlay.setSourceBounds(
+ new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
+ try {
+ mIntent.send(PhoneStatusBarService.this, 0, overlay);
+ } catch (PendingIntent.CanceledException e) {
+ // the stack trace isn't very helpful here. Just log the exception message.
+ Slog.w(TAG, "Sending contentIntent failed: " + e);
+ }
+ }
+
+ try {
+ mBarService.onNotificationClick(mPkg, mTag, mId);
+ } catch (RemoteException ex) {
+ // system process is dead if we're here.
+ }
+
+ // close the shade if it was open
+ animateCollapse();
+
+ // If this click was on the intruder alert, hide that instead
+ mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
+ }
+ }
+
+ private void tick(StatusBarNotification n) {
+ // Show the ticker if one is requested. Also don't do this
+ // until status bar window is attached to the window manager,
+ // because... well, what's the point otherwise? And trying to
+ // run a ticker without being attached will crash!
+ if (n.notification.tickerText != null && mStatusBarView.getWindowToken() != null) {
+ if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS
+ | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
+ mTicker.addEntry(n);
+ }
+ }
+ }
+
+ /**
+ * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
+ * about the failure.
+ *
+ * WARNING: this will call back into us. Don't hold any locks.
+ */
+ void handleNotificationError(IBinder key, StatusBarNotification n, String message) {
+ removeNotification(key);
+ try {
+ mBarService.onNotificationError(n.pkg, n.tag, n.id, n.uid, n.initialPid, message);
+ } catch (RemoteException ex) {
+ // The end is nigh.
+ }
+ }
+
+ private class MyTicker extends Ticker {
+ MyTicker(Context context, View sb) {
+ super(context, sb);
+ }
+
+ @Override
+ public void tickerStarting() {
+ mTicking = true;
+ mIcons.setVisibility(View.GONE);
+ mTickerView.setVisibility(View.VISIBLE);
+ mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null));
+ mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null));
+ if (mExpandedVisible) {
+ setDateViewVisibility(false, com.android.internal.R.anim.push_up_out);
+ }
+ }
+
+ @Override
+ public void tickerDone() {
+ mIcons.setVisibility(View.VISIBLE);
+ mTickerView.setVisibility(View.GONE);
+ mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null));
+ mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out,
+ mTickingDoneListener));
+ if (mExpandedVisible) {
+ setDateViewVisibility(true, com.android.internal.R.anim.push_down_in);
+ }
+ }
+
+ public void tickerHalting() {
+ mIcons.setVisibility(View.VISIBLE);
+ mTickerView.setVisibility(View.GONE);
+ mIcons.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
+ mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.fade_out,
+ mTickingDoneListener));
+ if (mExpandedVisible) {
+ setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
+ }
+ }
+ }
+
+ Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {;
+ public void onAnimationEnd(Animation animation) {
+ mTicking = false;
+ }
+ public void onAnimationRepeat(Animation animation) {
+ }
+ public void onAnimationStart(Animation animation) {
+ }
+ };
+
+ private Animation loadAnim(int id, Animation.AnimationListener listener) {
+ Animation anim = AnimationUtils.loadAnimation(PhoneStatusBarService.this, id);
+ if (listener != null) {
+ anim.setAnimationListener(listener);
+ }
+ return anim;
+ }
+
+ public String viewInfo(View v) {
+ return "(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
+ + " " + v.getWidth() + "x" + v.getHeight() + ")";
+ }
+
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump StatusBar from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ synchronized (mQueueLock) {
+ pw.println("Current Status Bar state:");
+ pw.println(" mExpanded=" + mExpanded
+ + ", mExpandedVisible=" + mExpandedVisible);
+ pw.println(" mTicking=" + mTicking);
+ pw.println(" mTracking=" + mTracking);
+ pw.println(" mAnimating=" + mAnimating
+ + ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel
+ + ", mAnimAccel=" + mAnimAccel);
+ pw.println(" mCurAnimationTime=" + mCurAnimationTime
+ + " mAnimLastTime=" + mAnimLastTime);
+ pw.println(" mDisplayHeight=" + mDisplayHeight
+ + " mAnimatingReveal=" + mAnimatingReveal
+ + " mViewDelta=" + mViewDelta);
+ pw.println(" mDisplayHeight=" + mDisplayHeight);
+ pw.println(" mExpandedParams: " + mExpandedParams);
+ pw.println(" mExpandedView: " + viewInfo(mExpandedView));
+ pw.println(" mExpandedDialog: " + mExpandedDialog);
+ pw.println(" mTrackingParams: " + mTrackingParams);
+ pw.println(" mTrackingView: " + viewInfo(mTrackingView));
+ pw.println(" mOngoingTitle: " + viewInfo(mOngoingTitle));
+ pw.println(" mOngoingItems: " + viewInfo(mOngoingItems));
+ pw.println(" mLatestTitle: " + viewInfo(mLatestTitle));
+ pw.println(" mLatestItems: " + viewInfo(mLatestItems));
+ pw.println(" mNoNotificationsTitle: " + viewInfo(mNoNotificationsTitle));
+ pw.println(" mCloseView: " + viewInfo(mCloseView));
+ pw.println(" mTickerView: " + viewInfo(mTickerView));
+ pw.println(" mScrollView: " + viewInfo(mScrollView)
+ + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY());
+ pw.println("mNotificationLinearLayout: " + viewInfo(mNotificationLinearLayout));
+ }
+ /*
+ synchronized (mNotificationData) {
+ int N = mNotificationData.ongoingCount();
+ pw.println(" ongoingCount.size=" + N);
+ for (int i=0; i<N; i++) {
+ StatusBarNotification n = mNotificationData.getOngoing(i);
+ pw.println(" [" + i + "] key=" + n.key + " view=" + n.view);
+ pw.println(" data=" + n.data);
+ }
+ N = mNotificationData.latestCount();
+ pw.println(" ongoingCount.size=" + N);
+ for (int i=0; i<N; i++) {
+ StatusBarNotification n = mNotificationData.getLatest(i);
+ pw.println(" [" + i + "] key=" + n.key + " view=" + n.view);
+ pw.println(" data=" + n.data);
+ }
+ }
+ */
+
+ if (false) {
+ pw.println("see the logcat for a dump of the views we have created.");
+ // must happen on ui thread
+ mHandler.post(new Runnable() {
+ public void run() {
+ mStatusBarView.getLocationOnScreen(mAbsPos);
+ Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+ + ") " + mStatusBarView.getWidth() + "x"
+ + mStatusBarView.getHeight());
+ mStatusBarView.debug();
+
+ mExpandedView.getLocationOnScreen(mAbsPos);
+ Slog.d(TAG, "mExpandedView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+ + ") " + mExpandedView.getWidth() + "x"
+ + mExpandedView.getHeight());
+ mExpandedView.debug();
+
+ mTrackingView.getLocationOnScreen(mAbsPos);
+ Slog.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+ + ") " + mTrackingView.getWidth() + "x"
+ + mTrackingView.getHeight());
+ mTrackingView.debug();
+ }
+ });
+ }
+ }
+
+ void onBarViewAttached() {
+ WindowManager.LayoutParams lp;
+ int pixelFormat;
+ Drawable bg;
+
+ /// ---------- Tracking View --------------
+ pixelFormat = PixelFormat.RGBX_8888;
+ bg = mTrackingView.getBackground();
+ if (bg != null) {
+ pixelFormat = bg.getOpacity();
+ }
+
+ lp = new WindowManager.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+ | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+ pixelFormat);
+// lp.token = mStatusBarView.getWindowToken();
+ lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+ lp.setTitle("TrackingView");
+ lp.y = mTrackingPosition;
+ mTrackingParams = lp;
+
+ WindowManagerImpl.getDefault().addView(mTrackingView, lp);
+ }
+
+ void onTrackingViewAttached() {
+ WindowManager.LayoutParams lp;
+ int pixelFormat;
+ Drawable bg;
+
+ /// ---------- Expanded View --------------
+ pixelFormat = PixelFormat.TRANSLUCENT;
+
+ final int disph = mDisplay.getHeight();
+ lp = mExpandedDialog.getWindow().getAttributes();
+ lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
+ lp.height = getExpandedHeight();
+ lp.x = 0;
+ mTrackingPosition = lp.y = -disph; // sufficiently large negative
+ lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
+ lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_DITHER
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ lp.format = pixelFormat;
+ lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+ lp.setTitle("StatusBarExpanded");
+ mExpandedDialog.getWindow().setAttributes(lp);
+ mExpandedDialog.getWindow().setFormat(pixelFormat);
+ mExpandedParams = lp;
+
+ mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+ mExpandedDialog.setContentView(mExpandedView,
+ new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ mExpandedDialog.getWindow().setBackgroundDrawable(null);
+ mExpandedDialog.show();
+ FrameLayout hack = (FrameLayout)mExpandedView.getParent();
+ }
+
+ void setDateViewVisibility(boolean visible, int anim) {
+ mDateView.setUpdates(visible);
+ mDateView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+ mDateView.startAnimation(loadAnim(anim, null));
+ }
+
+ void setNotificationIconVisibility(boolean visible, int anim) {
+ int old = mNotificationIcons.getVisibility();
+ int v = visible ? View.VISIBLE : View.INVISIBLE;
+ if (old != v) {
+ mNotificationIcons.setVisibility(v);
+ mNotificationIcons.startAnimation(loadAnim(anim, null));
+ }
+ }
+
+ void updateExpandedViewPos(int expandedPosition) {
+ if (SPEW) {
+ Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition
+ + " mTrackingParams.y=" + mTrackingParams.y
+ + " mTrackingPosition=" + mTrackingPosition);
+ }
+
+ int h = mStatusBarView.getHeight();
+ int disph = mDisplay.getHeight();
+
+ // If the expanded view is not visible, make sure they're still off screen.
+ // Maybe the view was resized.
+ if (!mExpandedVisible) {
+ if (mTrackingView != null) {
+ mTrackingPosition = -disph;
+ if (mTrackingParams != null) {
+ mTrackingParams.y = mTrackingPosition;
+ WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
+ }
+ }
+ if (mExpandedParams != null) {
+ mExpandedParams.y = -disph;
+ mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+ }
+ return;
+ }
+
+ // tracking view...
+ int pos;
+ if (expandedPosition == EXPANDED_FULL_OPEN) {
+ pos = h;
+ }
+ else if (expandedPosition == EXPANDED_LEAVE_ALONE) {
+ pos = mTrackingPosition;
+ }
+ else {
+ if (expandedPosition <= disph) {
+ pos = expandedPosition;
+ } else {
+ pos = disph;
+ }
+ pos -= disph-h;
+ }
+ mTrackingPosition = mTrackingParams.y = pos;
+ mTrackingParams.height = disph-h;
+ WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
+
+ if (mExpandedParams != null) {
+ mCloseView.getLocationInWindow(mPositionTmp);
+ final int closePos = mPositionTmp[1];
+
+ mExpandedContents.getLocationInWindow(mPositionTmp);
+ final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();
+
+ mExpandedParams.y = pos + mTrackingView.getHeight()
+ - (mTrackingParams.height-closePos) - contentsBottom;
+ int max = h;
+ if (mExpandedParams.y > max) {
+ mExpandedParams.y = max;
+ }
+ int min = mTrackingPosition;
+ if (mExpandedParams.y < min) {
+ mExpandedParams.y = min;
+ }
+
+ boolean visible = (mTrackingPosition + mTrackingView.getHeight()) > h;
+ if (!visible) {
+ // if the contents aren't visible, move the expanded view way off screen
+ // because the window itself extends below the content view.
+ mExpandedParams.y = -disph;
+ }
+ mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+
+ // As long as this isn't just a repositioning that's not supposed to affect
+ // the user's perception of what's showing, call to say that the visibility
+ // has changed. (Otherwise, someone else will call to do that).
+ if (expandedPosition != EXPANDED_LEAVE_ALONE) {
+ if (SPEW) Slog.d(TAG, "updateExpandedViewPos visibilityChanged(" + visible + ")");
+ visibilityChanged(visible);
+ }
+ }
+
+ if (SPEW) {
+ Slog.d(TAG, "updateExpandedViewPos after expandedPosition=" + expandedPosition
+ + " mTrackingParams.y=" + mTrackingParams.y
+ + " mTrackingPosition=" + mTrackingPosition
+ + " mExpandedParams.y=" + mExpandedParams.y
+ + " mExpandedParams.height=" + mExpandedParams.height);
+ }
+ }
+
+ int getExpandedHeight() {
+ return mDisplay.getHeight() - mStatusBarView.getHeight() - mCloseView.getHeight();
+ }
+
+ void updateExpandedHeight() {
+ if (mExpandedView != null) {
+ mExpandedParams.height = getExpandedHeight();
+ mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+ }
+ }
+
+ /**
+ * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
+ * This was added last-minute and is inconsistent with the way the rest of the notifications
+ * are handled, because the notification isn't really cancelled. The lights are just
+ * turned off. If any other notifications happen, the lights will turn back on. Steve says
+ * this is what he wants. (see bug 1131461)
+ */
+ void visibilityChanged(boolean visible) {
+ if (mPanelSlightlyVisible != visible) {
+ mPanelSlightlyVisible = visible;
+ try {
+ mBarService.onPanelRevealed();
+ } catch (RemoteException ex) {
+ // Won't fail unless the world has ended.
+ }
+ }
+ }
+
+ void performDisableActions(int net) {
+ int old = mDisabled;
+ int diff = net ^ old;
+ mDisabled = net;
+
+ // act accordingly
+ if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
+ if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
+ Slog.d(TAG, "DISABLE_EXPAND: yes");
+ animateCollapse();
+ }
+ }
+ if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+ if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+ Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
+ if (mTicking) {
+ mNotificationIcons.setVisibility(View.INVISIBLE);
+ mTicker.halt();
+ } else {
+ setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
+ }
+ } else {
+ Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
+ if (!mExpandedVisible) {
+ setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
+ }
+ }
+ } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+ if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+ mTicker.halt();
+ }
+ }
+ }
+
+ private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ try {
+ mBarService.onClearAllNotifications();
+ } catch (RemoteException ex) {
+ // system process is dead if we're here.
+ }
+ animateCollapse();
+ }
+ };
+
+ private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
+ || Intent.ACTION_SCREEN_OFF.equals(action)) {
+ //collapse();
+ }
+ else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+ updateResources();
+ }
+ }
+ };
+
+ private void setIntruderAlertVisibility(boolean vis) {
+ mIntruderAlertView.setVisibility(vis ? View.VISIBLE : View.GONE);
+ }
+
+ /**
+ * Reload some of our resources when the configuration changes.
+ *
+ * We don't reload everything when the configuration changes -- we probably
+ * should, but getting that smooth is tough. Someday we'll fix that. In the
+ * meantime, just update the things that we know change.
+ */
+ void updateResources() {
+ Resources res = getResources();
+
+ mClearButton.setText(getText(R.string.status_bar_clear_all_button));
+ mOngoingTitle.setText(getText(R.string.status_bar_ongoing_events_title));
+ mLatestTitle.setText(getText(R.string.status_bar_latest_events_title));
+ mNoNotificationsTitle.setText(getText(R.string.status_bar_no_notifications_title));
+
+ mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
+
+ if (false) Slog.v(TAG, "updateResources");
+ }
+
+ //
+ // tracing
+ //
+
+ void postStartTracing() {
+ mHandler.postDelayed(mStartTracing, 3000);
+ }
+
+ void vibrate() {
+ android.os.Vibrator vib = (android.os.Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
+ vib.vibrate(250);
+ }
+
+ Runnable mStartTracing = new Runnable() {
+ public void run() {
+ vibrate();
+ SystemClock.sleep(250);
+ Slog.d(TAG, "startTracing");
+ android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
+ mHandler.postDelayed(mStopTracing, 10000);
+ }
+ };
+
+ Runnable mStopTracing = new Runnable() {
+ public void run() {
+ android.os.Debug.stopMethodTracing();
+ Slog.d(TAG, "stopTracing");
+ vibrate();
+ }
+ };
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
index d2346e4..a64c3e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
@@ -17,188 +17,53 @@
package com.android.systemui.statusbar;
import android.app.Service;
-import com.android.internal.statusbar.IStatusBar;
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.statusbar.StatusBarIconList;
-import com.android.internal.statusbar.StatusBarNotification;
-
-import android.app.ActivityManagerNative;
-import android.app.Dialog;
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.app.StatusBarManager;
-import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.Message;
import android.os.ServiceManager;
-import android.os.SystemClock;
import android.util.Slog;
import android.util.Log;
-import android.view.Display;
import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
-import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.RemoteViews;
-import android.widget.ScrollView;
-import android.widget.TextView;
-import android.widget.FrameLayout;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Set;
-
-import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.StatusBarPolicy;
+import com.android.internal.statusbar.IStatusBar;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.statusbar.StatusBarNotification;
+import com.android.systemui.R;
-public class StatusBarService extends Service implements CommandQueue.Callbacks {
+public abstract class StatusBarService extends Service implements CommandQueue.Callbacks {
static final String TAG = "StatusBarService";
- static final boolean SPEW = false;
-
- public static final String ACTION_STATUSBAR_START
- = "com.android.internal.policy.statusbar.START";
-
- static final int EXPANDED_LEAVE_ALONE = -10000;
- static final int EXPANDED_FULL_OPEN = -10001;
-
- private static final int MSG_ANIMATE = 1000;
- private static final int MSG_ANIMATE_REVEAL = 1001;
- private static final int MSG_SHOW_INTRUDER = 1002;
- private static final int MSG_HIDE_INTRUDER = 1003;
-
- // will likely move to a resource or other tunable param at some point
- private static final int INTRUDER_ALERT_DECAY_MS = 10000;
-
- StatusBarPolicy mIconPolicy;
-
- CommandQueue mCommandQueue;
- IStatusBarService mBarService;
-
- int mIconSize;
- Display mDisplay;
- StatusBarView mStatusBarView;
- int mPixelFormat;
- H mHandler = new H();
- Object mQueueLock = new Object();
-
- // icons
- LinearLayout mIcons;
- IconMerger mNotificationIcons;
- LinearLayout mStatusIcons;
-
- // expanded notifications
- Dialog mExpandedDialog;
- ExpandedView mExpandedView;
- WindowManager.LayoutParams mExpandedParams;
- ScrollView mScrollView;
- View mNotificationLinearLayout;
- View mExpandedContents;
- // top bar
- TextView mNoNotificationsTitle;
- TextView mClearButton;
- // drag bar
- CloseDragHandle mCloseView;
- // ongoing
- NotificationData mOngoing = new NotificationData();
- TextView mOngoingTitle;
- LinearLayout mOngoingItems;
- // latest
- NotificationData mLatest = new NotificationData();
- TextView mLatestTitle;
- LinearLayout mLatestItems;
- // position
- int[] mPositionTmp = new int[2];
- boolean mExpanded;
- boolean mExpandedVisible;
-
- // the date view
- DateView mDateView;
- // the tracker view
- TrackingView mTrackingView;
- WindowManager.LayoutParams mTrackingParams;
- int mTrackingPosition; // the position of the top of the tracking view.
- private boolean mPanelSlightlyVisible;
+ protected CommandQueue mCommandQueue;
+ protected IStatusBarService mBarService;
- // ticker
- private Ticker mTicker;
- private View mTickerView;
- private boolean mTicking;
+ // Up-call methods
+ protected abstract View makeStatusBarView();
+ protected abstract int getStatusBarGravity();
- // Tracking finger for opening/closing.
- int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
- boolean mTracking;
- VelocityTracker mVelocityTracker;
-
- static final int ANIM_FRAME_DURATION = (1000/60);
-
- boolean mAnimating;
- long mCurAnimationTime;
- float mDisplayHeight;
- float mAnimY;
- float mAnimVel;
- float mAnimAccel;
- long mAnimLastTime;
- boolean mAnimatingReveal = false;
- int mViewDelta;
- int[] mAbsPos = new int[2];
-
- // for disabling the status bar
- int mDisabled = 0;
-
- private class ExpandedDialog extends Dialog {
- ExpandedDialog(Context context) {
- super(context, com.android.internal.R.style.Theme_Light_NoTitleBar);
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
- switch (event.getKeyCode()) {
- case KeyEvent.KEYCODE_BACK:
- if (!down) {
- animateCollapse();
- }
- return true;
- }
- return super.dispatchKeyEvent(event);
- }
+ /**
+ * Nobody binds to us.
+ */
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
}
-
@Override
public void onCreate() {
// First set up our views and stuff.
- mDisplay = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
- makeStatusBarView(this);
+ View sb = makeStatusBarView();
// Connect in to the status bar manager service
StatusBarIconList iconList = new StatusBarIconList();
@@ -236,1371 +101,22 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks
}
// Put up the view
- addStatusBarView();
-
- // Lastly, call to the icon policy to install/update all the icons.
- mIconPolicy = new StatusBarPolicy(this);
- }
-
- @Override
- public void onDestroy() {
- // we're never destroyed
- }
-
- // for immersive activities
- private View mIntruderAlertView;
-
- /**
- * Nobody binds to us.
- */
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
- // ================================================================================
- // Constructing the view
- // ================================================================================
- private void makeStatusBarView(Context context) {
- Resources res = context.getResources();
-
- mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
-
- ExpandedView expanded = (ExpandedView)View.inflate(context,
- R.layout.status_bar_expanded, null);
- expanded.mService = this;
-
- mIntruderAlertView = View.inflate(context, R.layout.intruder_alert, null);
- mIntruderAlertView.setVisibility(View.GONE);
- mIntruderAlertView.setClickable(true);
-
- StatusBarView sb = (StatusBarView)View.inflate(context, R.layout.status_bar, null);
- sb.mService = this;
-
- // figure out which pixel-format to use for the status bar.
- mPixelFormat = PixelFormat.TRANSLUCENT;
- Drawable bg = sb.getBackground();
- if (bg != null) {
- mPixelFormat = bg.getOpacity();
- }
-
- mStatusBarView = sb;
- mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons);
- mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons);
- mIcons = (LinearLayout)sb.findViewById(R.id.icons);
- mTickerView = sb.findViewById(R.id.ticker);
- mDateView = (DateView)sb.findViewById(R.id.date);
-
- mExpandedDialog = new ExpandedDialog(context);
- mExpandedView = expanded;
- mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout);
- mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle);
- mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems);
- mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle);
- mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems);
- mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle);
- mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button);
- mClearButton.setOnClickListener(mClearButtonListener);
- mScrollView = (ScrollView)expanded.findViewById(R.id.scroll);
- mNotificationLinearLayout = expanded.findViewById(R.id.notificationLinearLayout);
-
- mOngoingTitle.setVisibility(View.GONE);
- mLatestTitle.setVisibility(View.GONE);
-
- mTicker = new MyTicker(context, sb);
-
- TickerView tickerView = (TickerView)sb.findViewById(R.id.tickerText);
- tickerView.mTicker = mTicker;
-
- mTrackingView = (TrackingView)View.inflate(context, R.layout.status_bar_tracking, null);
- mTrackingView.mService = this;
- mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close);
- mCloseView.mService = this;
-
- mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
-
- // the more notifications icon
- StatusBarIconView moreView = new StatusBarIconView(this, "more");
- moreView.set(new StatusBarIcon(null, R.drawable.stat_notify_more, 0));
- mNotificationIcons.addMoreView(moreView,
- new LinearLayout.LayoutParams(mIconSize, mIconSize));
-
- // set the inital view visibility
- setAreThereNotifications();
- mDateView.setVisibility(View.INVISIBLE);
-
- // receive broadcasts
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- filter.addAction(Intent.ACTION_SCREEN_OFF);
- context.registerReceiver(mBroadcastReceiver, filter);
- }
-
- protected void addStatusBarView() {
- Resources res = getResources();
+ final Resources res = getResources();
final int height= res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
- final StatusBarView view = mStatusBarView;
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
height,
WindowManager.LayoutParams.TYPE_STATUS_BAR,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING,
PixelFormat.RGBX_8888);
- lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+ lp.gravity = getStatusBarGravity();
lp.setTitle("StatusBar");
// TODO lp.windowAnimations = R.style.Animation_StatusBar;
+ WindowManagerImpl.getDefault().addView(sb, lp);
- WindowManagerImpl.getDefault().addView(view, lp);
-
- lp = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
- PixelFormat.TRANSLUCENT);
- lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
- lp.y += height * 1.5; // FIXME
- lp.setTitle("IntruderAlert");
- lp.windowAnimations = com.android.internal.R.style.Animation_StatusBar_IntruderAlert;
-
- WindowManagerImpl.getDefault().addView(mIntruderAlertView, lp);
- }
-
- public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
- if (SPEW) Slog.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
- + " icon=" + icon);
- StatusBarIconView view = new StatusBarIconView(this, slot);
- view.set(icon);
- mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconSize, mIconSize));
- }
-
- public void updateIcon(String slot, int index, int viewIndex,
- StatusBarIcon old, StatusBarIcon icon) {
- if (SPEW) Slog.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
- + " old=" + old + " icon=" + icon);
- StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex);
- view.set(icon);
- }
-
- public void removeIcon(String slot, int index, int viewIndex) {
- if (SPEW) Slog.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex);
- mStatusIcons.removeViewAt(viewIndex);
- }
-
- public void addNotification(IBinder key, StatusBarNotification notification) {
- StatusBarIconView iconView = addNotificationViews(key, notification);
- if (iconView == null) return;
-
- boolean immersive = false;
- try {
- immersive = ActivityManagerNative.getDefault().isTopActivityImmersive();
- Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));
- } catch (RemoteException ex) {
- }
- if (immersive) {
- if ((notification.notification.flags & Notification.FLAG_HIGH_PRIORITY) != 0) {
- Slog.d(TAG, "Presenting high-priority notification in immersive activity");
- // @@@ special new transient ticker mode
- // 1. Populate mIntruderAlertView
-
- ImageView alertIcon = (ImageView) mIntruderAlertView.findViewById(R.id.alertIcon);
- TextView alertText = (TextView) mIntruderAlertView.findViewById(R.id.alertText);
- alertIcon.setImageDrawable(StatusBarIconView.getIcon(
- alertIcon.getContext(),
- iconView.getStatusBarIcon()));
- alertText.setText(notification.notification.tickerText);
-
- View button = mIntruderAlertView.findViewById(R.id.intruder_alert_content);
- button.setOnClickListener(
- new Launcher(notification.notification.contentIntent,
- notification.pkg, notification.tag, notification.id));
-
- // 2. Animate mIntruderAlertView in
- mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER);
-
- // 3. Set alarm to age the notification off (TODO)
- mHandler.removeMessages(MSG_HIDE_INTRUDER);
- mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS);
- }
- } else if (notification.notification.fullScreenIntent != null) {
- // not immersive & a full-screen alert should be shown
- Slog.d(TAG, "Notification has fullScreenIntent and activity is not immersive;"
- + " sending fullScreenIntent");
- try {
- notification.notification.fullScreenIntent.send();
- } catch (PendingIntent.CanceledException e) {
- }
- } else {
- // usual case: status bar visible & not immersive
-
- // show the ticker
- tick(notification);
- }
-
- // Recalculate the position of the sliding windows and the titles.
- setAreThereNotifications();
- updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
- }
-
- public void updateNotification(IBinder key, StatusBarNotification notification) {
- Slog.d(TAG, "updateNotification key=" + key + " notification=" + notification);
-
- NotificationData oldList;
- int oldIndex = mOngoing.findEntry(key);
- if (oldIndex >= 0) {
- oldList = mOngoing;
- } else {
- oldIndex = mLatest.findEntry(key);
- if (oldIndex < 0) {
- Slog.w(TAG, "updateNotification for unknown key: " + key);
- return;
- }
- oldList = mLatest;
- }
- final NotificationData.Entry oldEntry = oldList.getEntryAt(oldIndex);
- final StatusBarNotification oldNotification = oldEntry.notification;
- final RemoteViews oldContentView = oldNotification.notification.contentView;
-
- final RemoteViews contentView = notification.notification.contentView;
-
- if (false) {
- Slog.d(TAG, "old notification: when=" + oldNotification.notification.when
- + " ongoing=" + oldNotification.isOngoing()
- + " expanded=" + oldEntry.expanded
- + " contentView=" + oldContentView);
- Slog.d(TAG, "new notification: when=" + notification.notification.when
- + " ongoing=" + oldNotification.isOngoing()
- + " contentView=" + contentView);
- }
-
- // Can we just reapply the RemoteViews in place? If when didn't change, the order
- // didn't change.
- if (notification.notification.when == oldNotification.notification.when
- && notification.isOngoing() == oldNotification.isOngoing()
- && oldEntry.expanded != null
- && contentView != null && oldContentView != null
- && contentView.getPackage() != null
- && oldContentView.getPackage() != null
- && oldContentView.getPackage().equals(contentView.getPackage())
- && oldContentView.getLayoutId() == contentView.getLayoutId()) {
- if (SPEW) Slog.d(TAG, "reusing notification");
- oldEntry.notification = notification;
- try {
- // Reapply the RemoteViews
- contentView.reapply(this, oldEntry.content);
- // update the contentIntent
- final PendingIntent contentIntent = notification.notification.contentIntent;
- if (contentIntent != null) {
- oldEntry.content.setOnClickListener(new Launcher(contentIntent,
- notification.pkg, notification.tag, notification.id));
- }
- // Update the icon.
- final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
- notification.notification.icon, notification.notification.iconLevel,
- notification.notification.number);
- if (!oldEntry.icon.set(ic)) {
- handleNotificationError(key, notification, "Couldn't update icon: " + ic);
- return;
- }
- }
- catch (RuntimeException e) {
- // It failed to add cleanly. Log, and remove the view from the panel.
- Slog.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
- removeNotificationViews(key);
- addNotificationViews(key, notification);
- }
- } else {
- if (SPEW) Slog.d(TAG, "not reusing notification");
- removeNotificationViews(key);
- addNotificationViews(key, notification);
- }
-
- // Restart the ticker if it's still running
- tick(notification);
-
- // Recalculate the position of the sliding windows and the titles.
- setAreThereNotifications();
- updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
- }
-
- public void removeNotification(IBinder key) {
- if (SPEW) Slog.d(TAG, "removeNotification key=" + key);
- StatusBarNotification old = removeNotificationViews(key);
-
- if (old != null) {
- // Cancel the ticker if it's still running
- mTicker.removeEntry(old);
-
- // Recalculate the position of the sliding windows and the titles.
- setAreThereNotifications();
- updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
- }
- }
-
- private int chooseIconIndex(boolean isOngoing, int viewIndex) {
- final int latestSize = mLatest.size();
- if (isOngoing) {
- return latestSize + (mOngoing.size() - viewIndex);
- } else {
- return latestSize - viewIndex;
- }
- }
-
- View[] makeNotificationView(StatusBarNotification notification, ViewGroup parent) {
- Notification n = notification.notification;
- RemoteViews remoteViews = n.contentView;
- if (remoteViews == null) {
- return null;
- }
-
- // create the row view
- LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- View row = inflater.inflate(R.layout.status_bar_latest_event, parent, false);
-
- // bind the click event to the content area
- ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
- content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
- content.setOnFocusChangeListener(mFocusChangeListener);
- PendingIntent contentIntent = n.contentIntent;
- if (contentIntent != null) {
- content.setOnClickListener(new Launcher(contentIntent, notification.pkg,
- notification.tag, notification.id));
- }
-
- View expanded = null;
- Exception exception = null;
- try {
- expanded = remoteViews.apply(this, content);
- }
- catch (RuntimeException e) {
- exception = e;
- }
- if (expanded == null) {
- String ident = notification.pkg + "/0x" + Integer.toHexString(notification.id);
- Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
- return null;
- } else {
- content.addView(expanded);
- row.setDrawingCacheEnabled(true);
- }
-
- return new View[] { row, content, expanded };
- }
-
- StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) {
- NotificationData list;
- ViewGroup parent;
- final boolean isOngoing = notification.isOngoing();
- if (isOngoing) {
- list = mOngoing;
- parent = mOngoingItems;
- } else {
- list = mLatest;
- parent = mLatestItems;
- }
- // Construct the expanded view.
- final View[] views = makeNotificationView(notification, parent);
- if (views == null) {
- handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
- + notification);
- return null;
- }
- final View row = views[0];
- final View content = views[1];
- final View expanded = views[2];
- // Construct the icon.
- final StatusBarIconView iconView = new StatusBarIconView(this,
- notification.pkg + "/0x" + Integer.toHexString(notification.id));
- final StatusBarIcon ic = new StatusBarIcon(notification.pkg, notification.notification.icon,
- notification.notification.iconLevel, notification.notification.number);
- if (!iconView.set(ic)) {
- handleNotificationError(key, notification, "Coulding create icon: " + ic);
- return null;
- }
- // Add the expanded view.
- final int viewIndex = list.add(key, notification, row, content, expanded, iconView);
- parent.addView(row, viewIndex);
- // Add the icon.
- final int iconIndex = chooseIconIndex(isOngoing, viewIndex);
- mNotificationIcons.addView(iconView, iconIndex,
- new LinearLayout.LayoutParams(mIconSize, mIconSize));
- return iconView;
- }
-
- StatusBarNotification removeNotificationViews(IBinder key) {
- NotificationData.Entry entry = mOngoing.remove(key);
- if (entry == null) {
- entry = mLatest.remove(key);
- if (entry == null) {
- Slog.w(TAG, "removeNotification for unknown key: " + key);
- return null;
- }
- }
- // Remove the expanded view.
- ((ViewGroup)entry.row.getParent()).removeView(entry.row);
- // Remove the icon.
- ((ViewGroup)entry.icon.getParent()).removeView(entry.icon);
-
- return entry.notification;
- }
-
- private void setAreThereNotifications() {
- boolean ongoing = mOngoing.hasVisibleItems();
- boolean latest = mLatest.hasVisibleItems();
-
- // (no ongoing notifications are clearable)
- if (mLatest.hasClearableItems()) {
- mClearButton.setVisibility(View.VISIBLE);
- } else {
- mClearButton.setVisibility(View.INVISIBLE);
- }
-
- mOngoingTitle.setVisibility(ongoing ? View.VISIBLE : View.GONE);
- mLatestTitle.setVisibility(latest ? View.VISIBLE : View.GONE);
-
- if (ongoing || latest) {
- mNoNotificationsTitle.setVisibility(View.GONE);
- } else {
- mNoNotificationsTitle.setVisibility(View.VISIBLE);
- }
- }
-
-
- /**
- * State is one or more of the DISABLE constants from StatusBarManager.
- */
- public void disable(int state) {
- final int old = mDisabled;
- final int diff = state ^ old;
- mDisabled = state;
-
- if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
- if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
- Slog.d(TAG, "DISABLE_EXPAND: yes");
- animateCollapse();
- }
- }
- if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
- if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
- Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
- if (mTicking) {
- mTicker.halt();
- } else {
- setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
- }
- } else {
- Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
- if (!mExpandedVisible) {
- setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
- }
- }
- } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
- if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
- Slog.d(TAG, "DISABLE_NOTIFICATION_TICKER: yes");
- mTicker.halt();
- }
- }
- }
-
- /**
- * All changes to the status bar and notifications funnel through here and are batched.
- */
- private class H extends Handler {
- public void handleMessage(Message m) {
- switch (m.what) {
- case MSG_ANIMATE:
- doAnimation();
- break;
- case MSG_ANIMATE_REVEAL:
- doRevealAnimation();
- break;
- case MSG_SHOW_INTRUDER:
- setIntruderAlertVisibility(true);
- break;
- case MSG_HIDE_INTRUDER:
- setIntruderAlertVisibility(false);
- break;
- }
- }
- }
-
- View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() {
- public void onFocusChange(View v, boolean hasFocus) {
- // Because 'v' is a ViewGroup, all its children will be (un)selected
- // too, which allows marqueeing to work.
- v.setSelected(hasFocus);
- }
- };
-
- private void makeExpandedVisible() {
- if (SPEW) Slog.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
- if (mExpandedVisible) {
- return;
- }
- mExpandedVisible = true;
- visibilityChanged(true);
-
- updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
- mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
- mExpandedDialog.getWindow().setAttributes(mExpandedParams);
- mExpandedView.requestFocus(View.FOCUS_FORWARD);
- mTrackingView.setVisibility(View.VISIBLE);
-
- if (!mTicking) {
- setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
- }
- }
-
- public void animateExpand() {
- if (SPEW) Slog.d(TAG, "Animate expand: expanded=" + mExpanded);
- if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
- return ;
- }
- if (mExpanded) {
- return;
- }
-
- prepareTracking(0, true);
- performFling(0, 2000.0f, true);
- }
-
- public void animateCollapse() {
- if (SPEW) {
- Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
- + " mExpandedVisible=" + mExpandedVisible
- + " mExpanded=" + mExpanded
- + " mAnimating=" + mAnimating
- + " mAnimY=" + mAnimY
- + " mAnimVel=" + mAnimVel);
- }
-
- if (!mExpandedVisible) {
- return;
- }
-
- int y;
- if (mAnimating) {
- y = (int)mAnimY;
- } else {
- y = mDisplay.getHeight()-1;
- }
- // Let the fling think that we're open so it goes in the right direction
- // and doesn't try to re-open the windowshade.
- mExpanded = true;
- prepareTracking(y, false);
- performFling(y, -2000.0f, true);
- }
-
- void performExpand() {
- if (SPEW) Slog.d(TAG, "performExpand: mExpanded=" + mExpanded);
- if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
- return ;
- }
- if (mExpanded) {
- return;
- }
-
- mExpanded = true;
- makeExpandedVisible();
- updateExpandedViewPos(EXPANDED_FULL_OPEN);
-
- if (false) postStartTracing();
+ Slog.d(TAG, "Added status bar view w/ gravity 0x" + Integer.toHexString(lp.gravity));
}
-
- void performCollapse() {
- if (SPEW) Slog.d(TAG, "performCollapse: mExpanded=" + mExpanded
- + " mExpandedVisible=" + mExpandedVisible
- + " mTicking=" + mTicking);
-
- if (!mExpandedVisible) {
- return;
- }
- mExpandedVisible = false;
- visibilityChanged(false);
- mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
- mExpandedDialog.getWindow().setAttributes(mExpandedParams);
- mTrackingView.setVisibility(View.GONE);
-
- if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
- setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
- }
- if (mDateView.getVisibility() == View.VISIBLE) {
- setDateViewVisibility(false, com.android.internal.R.anim.fade_out);
- }
-
- if (!mExpanded) {
- return;
- }
- mExpanded = false;
- }
-
- void doAnimation() {
- if (mAnimating) {
- if (SPEW) Slog.d(TAG, "doAnimation");
- if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
- incrementAnim();
- if (SPEW) Slog.d(TAG, "doAnimation after mAnimY=" + mAnimY);
- if (mAnimY >= mDisplay.getHeight()-1) {
- if (SPEW) Slog.d(TAG, "Animation completed to expanded state.");
- mAnimating = false;
- updateExpandedViewPos(EXPANDED_FULL_OPEN);
- performExpand();
- }
- else if (mAnimY < mStatusBarView.getHeight()) {
- if (SPEW) Slog.d(TAG, "Animation completed to collapsed state.");
- mAnimating = false;
- updateExpandedViewPos(0);
- performCollapse();
- }
- else {
- updateExpandedViewPos((int)mAnimY);
- mCurAnimationTime += ANIM_FRAME_DURATION;
- mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
- }
- }
- }
-
- void stopTracking() {
- mTracking = false;
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
-
- void incrementAnim() {
- long now = SystemClock.uptimeMillis();
- float t = ((float)(now - mAnimLastTime)) / 1000; // ms -> s
- final float y = mAnimY;
- final float v = mAnimVel; // px/s
- final float a = mAnimAccel; // px/s/s
- mAnimY = y + (v*t) + (0.5f*a*t*t); // px
- mAnimVel = v + (a*t); // px/s
- mAnimLastTime = now; // ms
- //Slog.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY
- // + " mAnimAccel=" + mAnimAccel);
- }
-
- void doRevealAnimation() {
- final int h = mCloseView.getHeight() + mStatusBarView.getHeight();
- if (mAnimatingReveal && mAnimating && mAnimY < h) {
- incrementAnim();
- if (mAnimY >= h) {
- mAnimY = h;
- updateExpandedViewPos((int)mAnimY);
- } else {
- updateExpandedViewPos((int)mAnimY);
- mCurAnimationTime += ANIM_FRAME_DURATION;
- mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
- mCurAnimationTime);
- }
- }
- }
-
- void prepareTracking(int y, boolean opening) {
- mTracking = true;
- mVelocityTracker = VelocityTracker.obtain();
- if (opening) {
- mAnimAccel = 2000.0f;
- mAnimVel = 200;
- mAnimY = mStatusBarView.getHeight();
- updateExpandedViewPos((int)mAnimY);
- mAnimating = true;
- mAnimatingReveal = true;
- mHandler.removeMessages(MSG_ANIMATE);
- mHandler.removeMessages(MSG_ANIMATE_REVEAL);
- long now = SystemClock.uptimeMillis();
- mAnimLastTime = now;
- mCurAnimationTime = now + ANIM_FRAME_DURATION;
- mAnimating = true;
- mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
- mCurAnimationTime);
- makeExpandedVisible();
- } else {
- // it's open, close it?
- if (mAnimating) {
- mAnimating = false;
- mHandler.removeMessages(MSG_ANIMATE);
- }
- updateExpandedViewPos(y + mViewDelta);
- }
- }
-
- void performFling(int y, float vel, boolean always) {
- mAnimatingReveal = false;
- mDisplayHeight = mDisplay.getHeight();
-
- mAnimY = y;
- mAnimVel = vel;
-
- //Slog.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel);
-
- if (mExpanded) {
- if (!always && (
- vel > 200.0f
- || (y > (mDisplayHeight-25) && vel > -200.0f))) {
- // We are expanded, but they didn't move sufficiently to cause
- // us to retract. Animate back to the expanded position.
- mAnimAccel = 2000.0f;
- if (vel < 0) {
- mAnimVel = 0;
- }
- }
- else {
- // We are expanded and are now going to animate away.
- mAnimAccel = -2000.0f;
- if (vel > 0) {
- mAnimVel = 0;
- }
- }
- } else {
- if (always || (
- vel > 200.0f
- || (y > (mDisplayHeight/2) && vel > -200.0f))) {
- // We are collapsed, and they moved enough to allow us to
- // expand. Animate in the notifications.
- mAnimAccel = 2000.0f;
- if (vel < 0) {
- mAnimVel = 0;
- }
- }
- else {
- // We are collapsed, but they didn't move sufficiently to cause
- // us to retract. Animate back to the collapsed position.
- mAnimAccel = -2000.0f;
- if (vel > 0) {
- mAnimVel = 0;
- }
- }
- }
- //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel
- // + " mAnimAccel=" + mAnimAccel);
-
- long now = SystemClock.uptimeMillis();
- mAnimLastTime = now;
- mCurAnimationTime = now + ANIM_FRAME_DURATION;
- mAnimating = true;
- mHandler.removeMessages(MSG_ANIMATE);
- mHandler.removeMessages(MSG_ANIMATE_REVEAL);
- mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
- stopTracking();
- }
-
- boolean interceptTouchEvent(MotionEvent event) {
- if (SPEW) {
- Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
- + mDisabled);
- }
-
- if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
- return false;
- }
-
- final int statusBarSize = mStatusBarView.getHeight();
- final int hitSize = statusBarSize*2;
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- final int y = (int)event.getRawY();
-
- if (!mExpanded) {
- mViewDelta = statusBarSize - y;
- } else {
- mTrackingView.getLocationOnScreen(mAbsPos);
- mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y;
- }
- if ((!mExpanded && y < hitSize) ||
- (mExpanded && y > (mDisplay.getHeight()-hitSize))) {
-
- // We drop events at the edge of the screen to make the windowshade come
- // down by accident less, especially when pushing open a device with a keyboard
- // that rotates (like g1 and droid)
- int x = (int)event.getRawX();
- final int edgeBorder = mEdgeBorder;
- if (x >= edgeBorder && x < mDisplay.getWidth() - edgeBorder) {
- prepareTracking(y, !mExpanded);// opening if we're not already fully visible
- mVelocityTracker.addMovement(event);
- }
- }
- } else if (mTracking) {
- mVelocityTracker.addMovement(event);
- final int minY = statusBarSize + mCloseView.getHeight();
- if (event.getAction() == MotionEvent.ACTION_MOVE) {
- int y = (int)event.getRawY();
- if (mAnimatingReveal && y < minY) {
- // nothing
- } else {
- mAnimatingReveal = false;
- updateExpandedViewPos(y + mViewDelta);
- }
- } else if (event.getAction() == MotionEvent.ACTION_UP) {
- mVelocityTracker.computeCurrentVelocity(1000);
-
- float yVel = mVelocityTracker.getYVelocity();
- boolean negative = yVel < 0;
-
- float xVel = mVelocityTracker.getXVelocity();
- if (xVel < 0) {
- xVel = -xVel;
- }
- if (xVel > 150.0f) {
- xVel = 150.0f; // limit how much we care about the x axis
- }
-
- float vel = (float)Math.hypot(yVel, xVel);
- if (negative) {
- vel = -vel;
- }
-
- performFling((int)event.getRawY(), vel, false);
- }
-
- }
- return false;
- }
-
- private class Launcher implements View.OnClickListener {
- private PendingIntent mIntent;
- private String mPkg;
- private String mTag;
- private int mId;
-
- Launcher(PendingIntent intent, String pkg, String tag, int id) {
- mIntent = intent;
- mPkg = pkg;
- mTag = tag;
- mId = id;
- }
-
- public void onClick(View v) {
- try {
- // The intent we are sending is for the application, which
- // won't have permission to immediately start an activity after
- // the user switches to home. We know it is safe to do at this
- // point, so make sure new activity switches are now allowed.
- ActivityManagerNative.getDefault().resumeAppSwitches();
- } catch (RemoteException e) {
- }
-
- if (mIntent != null) {
- int[] pos = new int[2];
- v.getLocationOnScreen(pos);
- Intent overlay = new Intent();
- overlay.setSourceBounds(
- new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
- try {
- mIntent.send(StatusBarService.this, 0, overlay);
- } catch (PendingIntent.CanceledException e) {
- // the stack trace isn't very helpful here. Just log the exception message.
- Slog.w(TAG, "Sending contentIntent failed: " + e);
- }
- }
-
- try {
- mBarService.onNotificationClick(mPkg, mTag, mId);
- } catch (RemoteException ex) {
- // system process is dead if we're here.
- }
-
- // close the shade if it was open
- animateCollapse();
-
- // If this click was on the intruder alert, hide that instead
- mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
- }
- }
-
- private void tick(StatusBarNotification n) {
- // Show the ticker if one is requested. Also don't do this
- // until status bar window is attached to the window manager,
- // because... well, what's the point otherwise? And trying to
- // run a ticker without being attached will crash!
- if (n.notification.tickerText != null && mStatusBarView.getWindowToken() != null) {
- if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS
- | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
- mTicker.addEntry(n);
- }
- }
- }
-
- /**
- * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
- * about the failure.
- *
- * WARNING: this will call back into us. Don't hold any locks.
- */
- void handleNotificationError(IBinder key, StatusBarNotification n, String message) {
- removeNotification(key);
- try {
- mBarService.onNotificationError(n.pkg, n.tag, n.id, n.uid, n.initialPid, message);
- } catch (RemoteException ex) {
- // The end is nigh.
- }
- }
-
- private class MyTicker extends Ticker {
- MyTicker(Context context, StatusBarView sb) {
- super(context, sb);
- }
-
- @Override
- void tickerStarting() {
- if (SPEW) Slog.d(TAG, "tickerStarting");
- mTicking = true;
- mIcons.setVisibility(View.GONE);
- mTickerView.setVisibility(View.VISIBLE);
- mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null));
- mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null));
- if (mExpandedVisible) {
- setDateViewVisibility(false, com.android.internal.R.anim.push_up_out);
- }
- }
-
- @Override
- void tickerDone() {
- if (SPEW) Slog.d(TAG, "tickerDone");
- mTicking = false;
- mIcons.setVisibility(View.VISIBLE);
- mTickerView.setVisibility(View.GONE);
- mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null));
- mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out, null));
- if (mExpandedVisible) {
- setDateViewVisibility(true, com.android.internal.R.anim.push_down_in);
- }
- }
-
- void tickerHalting() {
- if (SPEW) Slog.d(TAG, "tickerHalting");
- mTicking = false;
- mIcons.setVisibility(View.VISIBLE);
- mTickerView.setVisibility(View.GONE);
- mIcons.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
- mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.fade_out, null));
- if (mExpandedVisible) {
- setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
- }
- }
- }
-
- private Animation loadAnim(int id, Animation.AnimationListener listener) {
- Animation anim = AnimationUtils.loadAnimation(StatusBarService.this, id);
- if (listener != null) {
- anim.setAnimationListener(listener);
- }
- return anim;
- }
-
- public String viewInfo(View v) {
- return "(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
- + " " + v.getWidth() + "x" + v.getHeight() + ")";
- }
-
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump StatusBar from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
- return;
- }
-
- synchronized (mQueueLock) {
- pw.println("Current Status Bar state:");
- pw.println(" mExpanded=" + mExpanded
- + ", mExpandedVisible=" + mExpandedVisible);
- pw.println(" mTicking=" + mTicking);
- pw.println(" mTracking=" + mTracking);
- pw.println(" mAnimating=" + mAnimating
- + ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel
- + ", mAnimAccel=" + mAnimAccel);
- pw.println(" mCurAnimationTime=" + mCurAnimationTime
- + " mAnimLastTime=" + mAnimLastTime);
- pw.println(" mDisplayHeight=" + mDisplayHeight
- + " mAnimatingReveal=" + mAnimatingReveal
- + " mViewDelta=" + mViewDelta);
- pw.println(" mDisplayHeight=" + mDisplayHeight);
- pw.println(" mExpandedParams: " + mExpandedParams);
- pw.println(" mExpandedView: " + viewInfo(mExpandedView));
- pw.println(" mExpandedDialog: " + mExpandedDialog);
- pw.println(" mTrackingParams: " + mTrackingParams);
- pw.println(" mTrackingView: " + viewInfo(mTrackingView));
- pw.println(" mOngoingTitle: " + viewInfo(mOngoingTitle));
- pw.println(" mOngoingItems: " + viewInfo(mOngoingItems));
- pw.println(" mLatestTitle: " + viewInfo(mLatestTitle));
- pw.println(" mLatestItems: " + viewInfo(mLatestItems));
- pw.println(" mNoNotificationsTitle: " + viewInfo(mNoNotificationsTitle));
- pw.println(" mCloseView: " + viewInfo(mCloseView));
- pw.println(" mTickerView: " + viewInfo(mTickerView));
- pw.println(" mScrollView: " + viewInfo(mScrollView)
- + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY());
- pw.println("mNotificationLinearLayout: " + viewInfo(mNotificationLinearLayout));
- }
- /*
- synchronized (mNotificationData) {
- int N = mNotificationData.ongoingCount();
- pw.println(" ongoingCount.size=" + N);
- for (int i=0; i<N; i++) {
- StatusBarNotification n = mNotificationData.getOngoing(i);
- pw.println(" [" + i + "] key=" + n.key + " view=" + n.view);
- pw.println(" data=" + n.data);
- }
- N = mNotificationData.latestCount();
- pw.println(" ongoingCount.size=" + N);
- for (int i=0; i<N; i++) {
- StatusBarNotification n = mNotificationData.getLatest(i);
- pw.println(" [" + i + "] key=" + n.key + " view=" + n.view);
- pw.println(" data=" + n.data);
- }
- }
- */
-
- if (false) {
- pw.println("see the logcat for a dump of the views we have created.");
- // must happen on ui thread
- mHandler.post(new Runnable() {
- public void run() {
- mStatusBarView.getLocationOnScreen(mAbsPos);
- Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
- + ") " + mStatusBarView.getWidth() + "x"
- + mStatusBarView.getHeight());
- mStatusBarView.debug();
-
- mExpandedView.getLocationOnScreen(mAbsPos);
- Slog.d(TAG, "mExpandedView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
- + ") " + mExpandedView.getWidth() + "x"
- + mExpandedView.getHeight());
- mExpandedView.debug();
-
- mTrackingView.getLocationOnScreen(mAbsPos);
- Slog.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
- + ") " + mTrackingView.getWidth() + "x"
- + mTrackingView.getHeight());
- mTrackingView.debug();
- }
- });
- }
- }
-
- void onBarViewAttached() {
- WindowManager.LayoutParams lp;
- int pixelFormat;
- Drawable bg;
-
- /// ---------- Tracking View --------------
- pixelFormat = PixelFormat.RGBX_8888;
- bg = mTrackingView.getBackground();
- if (bg != null) {
- pixelFormat = bg.getOpacity();
- }
-
- lp = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
- | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
- pixelFormat);
-// lp.token = mStatusBarView.getWindowToken();
- lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
- lp.setTitle("TrackingView");
- lp.y = mTrackingPosition;
- mTrackingParams = lp;
-
- WindowManagerImpl.getDefault().addView(mTrackingView, lp);
- }
-
- void onTrackingViewAttached() {
- WindowManager.LayoutParams lp;
- int pixelFormat;
- Drawable bg;
-
- /// ---------- Expanded View --------------
- pixelFormat = PixelFormat.TRANSLUCENT;
-
- final int disph = mDisplay.getHeight();
- lp = mExpandedDialog.getWindow().getAttributes();
- lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
- lp.height = getExpandedHeight();
- lp.x = 0;
- mTrackingPosition = lp.y = -disph; // sufficiently large negative
- lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
- lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_DITHER
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- lp.format = pixelFormat;
- lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
- lp.setTitle("StatusBarExpanded");
- mExpandedDialog.getWindow().setAttributes(lp);
- mExpandedDialog.getWindow().setFormat(pixelFormat);
- mExpandedParams = lp;
-
- mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
- mExpandedDialog.setContentView(mExpandedView,
- new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
- mExpandedDialog.getWindow().setBackgroundDrawable(null);
- mExpandedDialog.show();
- FrameLayout hack = (FrameLayout)mExpandedView.getParent();
- }
-
- void setDateViewVisibility(boolean visible, int anim) {
- mDateView.setUpdates(visible);
- mDateView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
- mDateView.startAnimation(loadAnim(anim, null));
- }
-
- void setNotificationIconVisibility(boolean visible, int anim) {
- int old = mNotificationIcons.getVisibility();
- int v = visible ? View.VISIBLE : View.INVISIBLE;
- if (old != v) {
- mNotificationIcons.setVisibility(v);
- mNotificationIcons.startAnimation(loadAnim(anim, null));
- }
- }
-
- void updateExpandedViewPos(int expandedPosition) {
- if (SPEW) {
- Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition
- + " mTrackingParams.y="
- + ((mTrackingParams == null) ? "???" : mTrackingParams.y)
- + " mTrackingPosition=" + mTrackingPosition);
- }
-
- int h = mStatusBarView.getHeight();
- int disph = mDisplay.getHeight();
-
- // If the expanded view is not visible, make sure they're still off screen.
- // Maybe the view was resized.
- if (!mExpandedVisible) {
- if (mTrackingView != null) {
- mTrackingPosition = -disph;
- if (mTrackingParams != null) {
- mTrackingParams.y = mTrackingPosition;
- WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
- }
- }
- if (mExpandedParams != null) {
- mExpandedParams.y = -disph;
- mExpandedDialog.getWindow().setAttributes(mExpandedParams);
- }
- return;
- }
-
- // tracking view...
- int pos;
- if (expandedPosition == EXPANDED_FULL_OPEN) {
- pos = h;
- }
- else if (expandedPosition == EXPANDED_LEAVE_ALONE) {
- pos = mTrackingPosition;
- }
- else {
- if (expandedPosition <= disph) {
- pos = expandedPosition;
- } else {
- pos = disph;
- }
- pos -= disph-h;
- }
- mTrackingPosition = mTrackingParams.y = pos;
- mTrackingParams.height = disph-h;
- WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
-
- if (mExpandedParams != null) {
- mCloseView.getLocationInWindow(mPositionTmp);
- final int closePos = mPositionTmp[1];
-
- mExpandedContents.getLocationInWindow(mPositionTmp);
- final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();
-
- mExpandedParams.y = pos + mTrackingView.getHeight()
- - (mTrackingParams.height-closePos) - contentsBottom;
- int max = h;
- if (mExpandedParams.y > max) {
- mExpandedParams.y = max;
- }
- int min = mTrackingPosition;
- if (mExpandedParams.y < min) {
- mExpandedParams.y = min;
- }
-
- boolean visible = (mTrackingPosition + mTrackingView.getHeight()) > h;
- if (!visible) {
- // if the contents aren't visible, move the expanded view way off screen
- // because the window itself extends below the content view.
- mExpandedParams.y = -disph;
- }
- mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-
- // As long as this isn't just a repositioning that's not supposed to affect
- // the user's perception of what's showing, call to say that the visibility
- // has changed. (Otherwise, someone else will call to do that).
- if (expandedPosition != EXPANDED_LEAVE_ALONE) {
- if (SPEW) Slog.d(TAG, "updateExpandedViewPos visibilityChanged(" + visible + ")");
- visibilityChanged(visible);
- }
- }
-
- if (SPEW) {
- Slog.d(TAG, "updateExpandedViewPos after expandedPosition=" + expandedPosition
- + " mTrackingParams.y=" + mTrackingParams.y
- + " mTrackingPosition=" + mTrackingPosition
- + " mExpandedParams.y=" + mExpandedParams.y
- + " mExpandedParams.height=" + mExpandedParams.height);
- }
- }
-
- int getExpandedHeight() {
- return mDisplay.getHeight() - mStatusBarView.getHeight() - mCloseView.getHeight();
- }
-
- void updateExpandedHeight() {
- if (mExpandedView != null) {
- mExpandedParams.height = getExpandedHeight();
- mExpandedDialog.getWindow().setAttributes(mExpandedParams);
- }
- }
-
- /**
- * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
- * This was added last-minute and is inconsistent with the way the rest of the notifications
- * are handled, because the notification isn't really cancelled. The lights are just
- * turned off. If any other notifications happen, the lights will turn back on. Steve says
- * this is what he wants. (see bug 1131461)
- */
- void visibilityChanged(boolean visible) {
- if (mPanelSlightlyVisible != visible) {
- mPanelSlightlyVisible = visible;
- try {
- mBarService.onPanelRevealed();
- } catch (RemoteException ex) {
- // Won't fail unless the world has ended.
- }
- }
- }
-
- void performDisableActions(int net) {
- int old = mDisabled;
- int diff = net ^ old;
- mDisabled = net;
-
- // act accordingly
- if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
- if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
- Slog.d(TAG, "DISABLE_EXPAND: yes");
- animateCollapse();
- }
- }
- if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
- if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
- Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
- if (mTicking) {
- mNotificationIcons.setVisibility(View.INVISIBLE);
- mTicker.halt();
- } else {
- setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
- }
- } else {
- Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
- if (!mExpandedVisible) {
- setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
- }
- }
- } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
- Slog.d(TAG, "DISABLE_NOTIFICATION_TICKER: "
- + (((net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0)
- ? "yes" : "no"));
- if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
- mTicker.halt();
- }
- }
- }
-
- private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
- public void onClick(View v) {
- try {
- mBarService.onClearAllNotifications();
- } catch (RemoteException ex) {
- // system process is dead if we're here.
- }
- animateCollapse();
- }
- };
-
- private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
- || Intent.ACTION_SCREEN_OFF.equals(action)) {
- //collapse();
- }
- else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
- updateResources();
- }
- }
- };
-
- private void setIntruderAlertVisibility(boolean vis) {
- mIntruderAlertView.setVisibility(vis ? View.VISIBLE : View.GONE);
- }
-
- /**
- * Reload some of our resources when the configuration changes.
- *
- * We don't reload everything when the configuration changes -- we probably
- * should, but getting that smooth is tough. Someday we'll fix that. In the
- * meantime, just update the things that we know change.
- */
- void updateResources() {
- Resources res = getResources();
-
- mClearButton.setText(getText(R.string.status_bar_clear_all_button));
- mOngoingTitle.setText(getText(R.string.status_bar_ongoing_events_title));
- mLatestTitle.setText(getText(R.string.status_bar_latest_events_title));
- mNoNotificationsTitle.setText(getText(R.string.status_bar_no_notifications_title));
-
- mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
-
- if (false) Slog.v(TAG, "updateResources");
- }
-
- //
- // tracing
- //
-
- void postStartTracing() {
- mHandler.postDelayed(mStartTracing, 3000);
- }
-
- void vibrate() {
- android.os.Vibrator vib = (android.os.Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
- vib.vibrate(250);
- }
-
- Runnable mStartTracing = new Runnable() {
- public void run() {
- vibrate();
- SystemClock.sleep(250);
- Slog.d(TAG, "startTracing");
- android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
- mHandler.postDelayed(mStopTracing, 10000);
- }
- };
-
- Runnable mStopTracing = new Runnable() {
- public void run() {
- android.os.Debug.stopMethodTracing();
- Slog.d(TAG, "stopTracing");
- vibrate();
- }
- };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
index 1e140b9..20fc41f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
+import android.graphics.Rect;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.MotionEvent;
@@ -34,7 +35,7 @@ public class StatusBarView extends FrameLayout {
static final int DIM_ANIM_TIME = 400;
- StatusBarService mService;
+ PhoneStatusBarService mService;
boolean mTracking;
int mStartX, mStartY;
ViewGroup mNotificationIcons;
@@ -46,6 +47,9 @@ public class StatusBarView extends FrameLayout {
int mStartAlpha = 0, mEndAlpha = 0;
long mEndTime = 0;
+ Rect mButtonBounds = new Rect();
+ boolean mCapturingEvents = true;
+
public StatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -94,7 +98,7 @@ public class StatusBarView extends FrameLayout {
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
- mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE);
+ mService.updateExpandedViewPos(PhoneStatusBarService.EXPANDED_LEAVE_ALONE);
}
@Override
@@ -177,6 +181,9 @@ public class StatusBarView extends FrameLayout {
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
+ if (!mCapturingEvents) {
+ return false;
+ }
if (event.getAction() != MotionEvent.ACTION_DOWN) {
mService.interceptTouchEvent(event);
}
@@ -185,6 +192,13 @@ public class StatusBarView extends FrameLayout {
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ if (mButtonBounds.contains((int)event.getX(), (int)event.getY())) {
+ mCapturingEvents = false;
+ return false;
+ }
+ }
+ mCapturingEvents = true;
return mService.interceptTouchEvent(event)
? true : super.onInterceptTouchEvent(event);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java b/packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java
index 3a697a6..e7b0509 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java
@@ -141,7 +141,7 @@ public abstract class Ticker {
}
};
- Ticker(Context context, StatusBarView sb) {
+ public Ticker(Context context, View sb) {
mContext = context;
mTickerView = sb.findViewById(R.id.ticker);
@@ -163,7 +163,7 @@ public abstract class Ticker {
}
- void addEntry(StatusBarNotification n) {
+ public void addEntry(StatusBarNotification n) {
int initialCount = mSegments.size();
// If what's being displayed has the same text and icon, just drop it
@@ -212,7 +212,7 @@ public abstract class Ticker {
}
}
- void removeEntry(StatusBarNotification n) {
+ public void removeEntry(StatusBarNotification n) {
for (int i=mSegments.size()-1; i>=0; i--) {
Segment seg = mSegments.get(i);
if (n.id == seg.notification.id && n.pkg.equals(seg.notification.pkg)) {
@@ -221,13 +221,13 @@ public abstract class Ticker {
}
}
- void halt() {
+ public void halt() {
mHandler.removeCallbacks(mAdvanceTicker);
mSegments.clear();
tickerHalting();
}
- void reflowText() {
+ public void reflowText() {
if (mSegments.size() > 0) {
Segment seg = mSegments.get(0);
CharSequence text = seg.getText();
@@ -266,8 +266,8 @@ public abstract class Ticker {
mHandler.postDelayed(mAdvanceTicker, TICKER_SEGMENT_DELAY);
}
- abstract void tickerStarting();
- abstract void tickerDone();
- abstract void tickerHalting();
+ public abstract void tickerStarting();
+ public abstract void tickerDone();
+ public abstract void tickerHalting();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/TickerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/TickerView.java
index 9749ae4..8140811 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/TickerView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TickerView.java
@@ -34,5 +34,9 @@ public class TickerView extends TextSwitcher
super.onSizeChanged(w, h, oldw, oldh);
mTicker.reflowText();
}
+
+ public void setTicker(Ticker t) {
+ mTicker = t;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java b/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java
index 9108eee..c59eb6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java
@@ -26,7 +26,7 @@ import android.widget.LinearLayout;
public class TrackingView extends LinearLayout {
final Display mDisplay;
- StatusBarService mService;
+ PhoneStatusBarService mService;
boolean mTracking;
int mStartX, mStartY;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationIconArea.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationIconArea.java
new file mode 100644
index 0000000..7c7d74c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationIconArea.java
@@ -0,0 +1,56 @@
+/*
+ * 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.tablet;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+
+
+public class NotificationIconArea extends LinearLayout {
+ private static final String TAG = "NotificationIconArea";
+
+ IconLayout mIconLayout;
+ DraggerView mDraggerView;
+
+ public NotificationIconArea(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ mIconLayout = (IconLayout)findViewById(R.id.icons);
+ mDraggerView = (DraggerView) findViewById(R.id.handle);
+ }
+
+ static class IconLayout extends LinearLayout {
+ public IconLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+ }
+
+ static class DraggerView extends View {
+ public DraggerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SystemPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SystemPanel.java
new file mode 100644
index 0000000..a03393b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SystemPanel.java
@@ -0,0 +1,403 @@
+/*
+ * 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.tablet;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.Service;
+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.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.media.AudioManager;
+import android.net.NetworkInfo;
+import android.net.wifi.SupplicantState;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IPowerManager;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RemoteViews;
+import android.widget.ScrollView;
+import android.widget.TextSwitcher;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.util.List;
+
+import com.android.systemui.statusbar.*;
+import com.android.systemui.R;
+
+public class SystemPanel extends LinearLayout {
+ private static final String TAG = "SystemPanel";
+
+ private static final int MINIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_DIM + 5;
+ private static final int MAXIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_ON;
+ private static final int DEFAULT_BACKLIGHT = (int) (android.os.Power.BRIGHTNESS_ON * 0.4f);
+
+
+ private TabletStatusBarService mBar;
+ private boolean mAirplaneMode;
+
+ private ImageButton mBrightnessButton;
+ private ImageButton mSoundButton;
+ private ImageButton mOrientationButton;
+ private ImageButton mAirplaneButton;
+
+ private ImageView mBatteryMeter;
+ private ImageView mSignalMeter;
+
+ private TextView mBatteryText;
+ private TextView mSignalText;
+
+ private final AudioManager mAudioManager;
+ private final WifiManager mWifiManager;
+
+
+ private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
+ mSoundButton.setAlpha(getSilentMode() ? 0x7F : 0xFF);
+ } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
+ updateBattery(intent);
+ } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)
+ || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)
+ || action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)
+ || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+ updateWifi(intent);
+ }
+ }
+ };
+
+ boolean mWifiEnabled, mWifiConnected;
+ int mWifiLevel;
+ String mWifiSsid;
+
+ private void updateWifi(Intent intent) {
+ if (TabletStatusBarService.DEBUG)
+ Slog.d(TabletStatusBarService.TAG, "updateWifi: " + intent);
+
+ final String action = intent.getAction();
+ final boolean wasConnected = mWifiConnected;
+
+ 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);
+ mWifiConnected = networkInfo != null && networkInfo.isConnected();
+ } else if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) {
+ final NetworkInfo.DetailedState detailedState = WifiInfo.getDetailedStateOf(
+ (SupplicantState)intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE));
+ mWifiConnected = detailedState == NetworkInfo.DetailedState.CONNECTED;
+ } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
+ final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
+ int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 6) * 20;
+ mWifiLevel = mWifiConnected ? newSignalLevel : 0;
+ }
+
+ if (mWifiConnected && !wasConnected) {
+ WifiInfo info = mWifiManager.getConnectionInfo();
+ if (TabletStatusBarService.DEBUG)
+ Slog.d(TabletStatusBarService.TAG, "updateWifi: just connected: info=" + info);
+
+ if (info != null) {
+ // grab the initial signal strength
+ mWifiLevel = WifiManager.calculateSignalLevel(info.getRssi(), 101);
+
+ // find the SSID
+ mWifiSsid = info.getSSID();
+ if (mWifiSsid == null) {
+ // 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()) {
+ mWifiSsid = net.SSID;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (!mWifiEnabled) {
+ mWifiSsid = "disabled";
+ mWifiLevel = 0;
+ } else if (!mWifiConnected) {
+ mWifiSsid = "disconnected";
+ mWifiLevel = 0;
+ } else if (mWifiSsid == null) {
+ mWifiSsid = "unknown";
+ }
+
+ mSignalMeter.setImageResource(R.drawable.signal);
+ mSignalMeter.setImageLevel(mWifiLevel);
+ mSignalText.setText(String.format("Wi-Fi: %s", mWifiSsid)); // XXX: localize
+
+ // hack for now
+ mBar.setWifiMeter(mWifiLevel);
+ }
+
+ public void setBar(TabletStatusBarService bar) {
+ mBar = bar;
+ }
+
+ public void updateBattery(Intent intent) {
+ final int level = intent.getIntExtra("level", 0);
+ final boolean plugged = intent.getIntExtra("plugged", 0) != 0;
+
+ mBatteryMeter.setImageResource(plugged ? R.drawable.battery_charging : R.drawable.battery);
+ mBatteryMeter.setImageLevel(level);
+ mBatteryText.setText(String.format("Battery: %d%%", level));
+
+ // hack for now
+ mBar.setBatteryMeter(level, plugged);
+ }
+
+ public SystemPanel(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public SystemPanel(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ // get notified of phone state changes
+ TelephonyManager telephonyManager =
+ (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+ telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
+
+ // wifi status info
+ mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+
+ // audio status notifications
+ mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ }
+
+ public void onAttachedToWindow() {
+ TextView settingsButton = (TextView)findViewById(R.id.settings_button);
+ settingsButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ getContext().startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ mBar.animateCollapse();
+ }});
+
+ mBrightnessButton = (ImageButton)findViewById(R.id.brightness);
+ mBrightnessButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ rotateBrightness();
+ }
+ });
+
+ mSoundButton = (ImageButton)findViewById(R.id.sound);
+ mSoundButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ setSilentMode(!getSilentMode());
+ mSoundButton.setAlpha(getSilentMode() ? 0x7F : 0xFF);
+ }
+ });
+ mOrientationButton = (ImageButton)findViewById(R.id.orientation);
+ mOrientationButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ Toast.makeText(getContext(), "Orientation control not implemented; please adjust neck angle.", Toast.LENGTH_SHORT).show();
+ }
+ });
+
+ mAirplaneButton = (ImageButton)findViewById(R.id.airplane);
+ mAirplaneButton.setAlpha(mAirplaneMode ? 0xFF : 0x7F);
+ mAirplaneButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ boolean newMode = !getAirplaneMode();
+ Toast.makeText(getContext(), "Attempting to turn "
+ + (newMode ? "on" : "off") + " airplane mode (flaky).",
+ Toast.LENGTH_SHORT).show();
+ setAirplaneMode(newMode);
+ }
+ });
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
+ filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
+ filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
+ getContext().registerReceiver(mReceiver, filter);
+
+ mBatteryMeter = (ImageView)findViewById(R.id.battery_meter);
+ mBatteryMeter.setImageResource(R.drawable.battery);
+ mBatteryMeter.setImageLevel(0);
+ mSignalMeter = (ImageView)findViewById(R.id.signal_meter);
+ mBatteryMeter.setImageResource(R.drawable.signal);
+ mBatteryMeter.setImageLevel(0);
+
+ mBatteryText = (TextView)findViewById(R.id.battery_info);
+ mSignalText = (TextView)findViewById(R.id.signal_info);
+ }
+
+ public void onDetachedFromWindow() {
+ getContext().unregisterReceiver(mReceiver);
+ }
+
+ // ----------------------------------------------------------------------
+
+// private boolean isAutoBrightness() {
+// Context context = getContext();
+// try {
+// IPowerManager power = IPowerManager.Stub.asInterface(
+// ServiceManager.getService("power"));
+// if (power != null) {
+// int brightnessMode = Settings.System.getInt(context.getContentResolver(),
+// Settings.System.SCREEN_BRIGHTNESS_MODE);
+// return brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
+// }
+// } catch (RemoteException e) {
+// } catch (Settings.SettingNotFoundException e) {
+// }
+// return false;
+// }
+
+ private void rotateBrightness() {
+ int alpha = 0xFF;
+ Context context = getContext();
+ try {
+ IPowerManager power = IPowerManager.Stub.asInterface(
+ ServiceManager.getService("power"));
+ if (power != null) {
+ ContentResolver cr = context.getContentResolver();
+ int brightness = Settings.System.getInt(cr,
+ Settings.System.SCREEN_BRIGHTNESS);
+ int brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
+ //Only get brightness setting if available
+ if (context.getResources().getBoolean(
+ com.android.internal.R.bool.config_automatic_brightness_available)) {
+ brightnessMode = Settings.System.getInt(cr,
+ Settings.System.SCREEN_BRIGHTNESS_MODE);
+ }
+
+ // Rotate AUTO -> MINIMUM -> DEFAULT -> MAXIMUM
+ // Technically, not a toggle...
+ if (brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) {
+ brightness = MINIMUM_BACKLIGHT;
+ brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
+ alpha = 0x40;
+ } else if (brightness < DEFAULT_BACKLIGHT) {
+ brightness = DEFAULT_BACKLIGHT;
+ alpha = 0xC0;
+ } else if (brightness < MAXIMUM_BACKLIGHT) {
+ brightness = MAXIMUM_BACKLIGHT;
+ alpha = 0xFF;
+ } else {
+ brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
+ brightness = MINIMUM_BACKLIGHT;
+ alpha = 0x60;
+ }
+
+ if (context.getResources().getBoolean(
+ com.android.internal.R.bool.config_automatic_brightness_available)) {
+ // Set screen brightness mode (automatic or manual)
+ Settings.System.putInt(context.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ brightnessMode);
+ } else {
+ // Make sure we set the brightness if automatic mode isn't available
+ brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
+ }
+ if (brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL) {
+ power.setBacklightBrightness(brightness);
+ Settings.System.putInt(cr, Settings.System.SCREEN_BRIGHTNESS, brightness);
+ }
+ }
+ } catch (RemoteException e) {
+ } catch (Settings.SettingNotFoundException e) {
+ }
+
+ mBrightnessButton.setAlpha(alpha);
+ }
+
+ PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+ @Override
+ public void onServiceStateChanged(ServiceState serviceState) {
+ Slog.d(TAG, "phone service state changed: " + serviceState.getState());
+ mAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF;
+ if (mAirplaneButton != null) {
+ mAirplaneButton.setAlpha(mAirplaneMode ? 0xFF : 0x7F);
+ }
+ }
+ };
+
+ private boolean getAirplaneMode() {
+ return mAirplaneMode;
+ }
+
+ private void setAirplaneMode(boolean on) {
+ Settings.System.putInt(
+ mContext.getContentResolver(),
+ Settings.System.AIRPLANE_MODE_ON,
+ on ? 1 : 0);
+ Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ intent.putExtra("state", on);
+ getContext().sendBroadcast(intent);
+ }
+
+ boolean getSilentMode() {
+ return mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
+ }
+
+ void setSilentMode(boolean on) {
+ if (on) {
+ mAudioManager.setRingerMode((Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.VIBRATE_IN_SILENT, 1) == 1)
+ ? AudioManager.RINGER_MODE_VIBRATE
+ : AudioManager.RINGER_MODE_SILENT);
+ } else {
+ mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
new file mode 100644
index 0000000..18b9b41
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
@@ -0,0 +1,698 @@
+/*
+ * 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.tablet;
+
+import android.animation.Animator;
+import android.app.ActivityManagerNative;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.app.StatusBarManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RemoteViews;
+import android.widget.ScrollView;
+import android.widget.TextSwitcher;
+import android.widget.TextView;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.statusbar.StatusBarNotification;
+
+import com.android.systemui.statusbar.*;
+import com.android.systemui.R;
+
+public class TabletStatusBarService extends StatusBarService {
+ public static final boolean DEBUG = false;
+ public static final String TAG = "TabletStatusBar";
+
+
+
+ int mIconSize;
+
+ H mHandler = new H();
+
+ // tracking all current notifications
+ private NotificationData mNotns = new NotificationData();
+
+ View mStatusBarView;
+ NotificationIconArea mNotificationIconArea;
+
+ View mNotificationPanel;
+ SystemPanel mSystemPanel;
+
+ ViewGroup mPile;
+ TextView mClearButton;
+
+ ImageView mBatteryMeter;
+ ImageView mSignalMeter;
+
+ NotificationIconArea.IconLayout mIconLayout;
+
+ KickerController mKicker;
+ View mKickerView;
+ boolean mTicking;
+ boolean mExpandedVisible;
+
+ // for disabling the status bar
+ int mDisabled = 0;
+
+ protected void addPanelWindows() {
+ mNotificationPanel = View.inflate(this, R.layout.sysbar_panel_notifications, null);
+ mSystemPanel = (SystemPanel) View.inflate(this, R.layout.sysbar_panel_system, null);
+
+ mNotificationPanel.setVisibility(View.GONE);
+ mSystemPanel.setVisibility(View.GONE);
+
+ final Resources res = getResources();
+ final int barHeight= res.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height);
+
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ 400, // ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+ PixelFormat.TRANSLUCENT);
+ lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
+ lp.setTitle("NotificationPanel");
+ lp.windowAnimations = com.android.internal.R.style.Animation_SlidingCard;
+
+ WindowManagerImpl.getDefault().addView(mNotificationPanel, lp);
+
+ lp = new WindowManager.LayoutParams(
+ 500, // ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+ PixelFormat.TRANSLUCENT);
+ lp.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
+ lp.setTitle("SystemPanel");
+ lp.windowAnimations = com.android.internal.R.style.Animation_SlidingCard;
+
+ WindowManagerImpl.getDefault().addView(mSystemPanel, lp);
+ mSystemPanel.setBar(this);
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate(); // will add the main bar view
+ }
+
+ protected View makeStatusBarView() {
+ Resources res = getResources();
+
+ mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
+
+ final View sb = View.inflate(this, R.layout.status_bar, null);
+ mStatusBarView = sb;
+
+ // the more notifications icon
+ mNotificationIconArea = (NotificationIconArea)sb.findViewById(R.id.notificationIcons);
+
+ // where the icons go
+ mIconLayout = (NotificationIconArea.IconLayout) sb.findViewById(R.id.icons);
+
+ mKicker = new KickerController((Context)this, mStatusBarView);
+
+ // System info (center)
+ mBatteryMeter = (ImageView) sb.findViewById(R.id.battery);
+ mSignalMeter = (ImageView) sb.findViewById(R.id.signal);
+
+ // Add the windows
+ addPanelWindows();
+
+ mPile = (ViewGroup)mNotificationPanel.findViewById(R.id.content);
+ mPile.removeAllViews();
+
+ ScrollView scroller = (ScrollView)mPile.getParent();
+ scroller.setFillViewport(true);
+
+ mClearButton = (TextView)mNotificationPanel.findViewById(R.id.clear_all_button);
+ mClearButton.setOnClickListener(mClearButtonListener);
+
+ return sb;
+ }
+
+ protected int getStatusBarGravity() {
+ return Gravity.BOTTOM | Gravity.FILL_HORIZONTAL;
+ }
+
+ private class H extends Handler {
+ public static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
+ public static final int MSG_CLOSE_NOTIFICATION_PANEL = 1001;
+ public static final int MSG_OPEN_SYSTEM_PANEL = 1010;
+ public static final int MSG_CLOSE_SYSTEM_PANEL = 1011;
+ public void handleMessage(Message m) {
+ switch (m.what) {
+ case MSG_OPEN_NOTIFICATION_PANEL:
+ if (DEBUG) Slog.d(TAG, "opening notifications panel");
+ mNotificationPanel.setVisibility(View.VISIBLE);
+ mExpandedVisible = true;
+ break;
+ case MSG_CLOSE_NOTIFICATION_PANEL:
+ if (DEBUG) Slog.d(TAG, "closing notifications panel");
+ mNotificationPanel.setVisibility(View.GONE);
+ mExpandedVisible = false;
+ break;
+ case MSG_OPEN_SYSTEM_PANEL:
+ if (DEBUG) Slog.d(TAG, "opening system panel");
+ mSystemPanel.setVisibility(View.VISIBLE);
+ break;
+ case MSG_CLOSE_SYSTEM_PANEL:
+ if (DEBUG) Slog.d(TAG, "closing system panel");
+ mSystemPanel.setVisibility(View.GONE);
+ break;
+ }
+ }
+ }
+
+ public void setBatteryMeter(int level, boolean plugged) {
+ if (DEBUG) Slog.d(TAG, "battery=" + level + (plugged ? " - plugged" : " - unplugged"));
+ mBatteryMeter.setImageResource(plugged ? R.drawable.battery_charging : R.drawable.battery);
+ mBatteryMeter.setImageLevel(level);
+ }
+
+ public void setWifiMeter(int level) {
+ if (DEBUG) Slog.d(TAG, "wifi=" + level);
+ mSignalMeter.setImageResource(R.drawable.signal);
+ mSignalMeter.setImageLevel(level);
+ }
+
+ public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
+ if (DEBUG) Slog.d(TAG, "addIcon(" + slot + ") -> " + icon);
+ }
+
+ public void updateIcon(String slot, int index, int viewIndex,
+ StatusBarIcon old, StatusBarIcon icon) {
+ if (DEBUG) Slog.d(TAG, "updateIcon(" + slot + ") -> " + icon);
+ }
+
+ public void removeIcon(String slot, int index, int viewIndex) {
+ if (DEBUG) Slog.d(TAG, "removeIcon(" + slot + ")");
+ }
+
+ public void addNotification(IBinder key, StatusBarNotification notification) {
+ if (DEBUG) Slog.d(TAG, "addNotification(" + key + " -> " + notification + ")");
+ addNotificationViews(key, notification);
+
+ boolean immersive = false;
+ try {
+ immersive = ActivityManagerNative.getDefault().isTopActivityImmersive();
+ Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));
+ } catch (RemoteException ex) {
+ }
+ if (immersive) {
+ // TODO: immersive mode popups for tablet
+ } else if (notification.notification.fullScreenIntent != null) {
+ // not immersive & a full-screen alert should be shown
+ Slog.d(TAG, "Notification has fullScreenIntent and activity is not immersive;"
+ + " sending fullScreenIntent");
+ try {
+ notification.notification.fullScreenIntent.send();
+ } catch (PendingIntent.CanceledException e) {
+ }
+ } else {
+ // tick()
+ }
+ }
+
+ public void updateNotification(IBinder key, StatusBarNotification notification) {
+ if (DEBUG) Slog.d(TAG, "updateNotification(" + key + " -> " + notification + ") // TODO");
+
+ final NotificationData.Entry oldEntry = mNotns.findByKey(key);
+ if (oldEntry == null) {
+ Slog.w(TAG, "updateNotification for unknown key: " + key);
+ return;
+ }
+
+ final StatusBarNotification oldNotification = oldEntry.notification;
+ final RemoteViews oldContentView = oldNotification.notification.contentView;
+
+ final RemoteViews contentView = notification.notification.contentView;
+
+ if (false) {
+ Slog.d(TAG, "old notification: when=" + oldNotification.notification.when
+ + " ongoing=" + oldNotification.isOngoing()
+ + " expanded=" + oldEntry.expanded
+ + " contentView=" + oldContentView);
+ Slog.d(TAG, "new notification: when=" + notification.notification.when
+ + " ongoing=" + oldNotification.isOngoing()
+ + " contentView=" + contentView);
+ }
+
+ // Can we just reapply the RemoteViews in place? If when didn't change, the order
+ // didn't change.
+ if (notification.notification.when == oldNotification.notification.when
+ && notification.isOngoing() == oldNotification.isOngoing()
+ && oldEntry.expanded != null
+ && contentView != null
+ && oldContentView != null
+ && contentView.getPackage() != null
+ && oldContentView.getPackage() != null
+ && oldContentView.getPackage().equals(contentView.getPackage())
+ && oldContentView.getLayoutId() == contentView.getLayoutId()) {
+ if (DEBUG) Slog.d(TAG, "reusing notification for key: " + key);
+ oldEntry.notification = notification;
+ try {
+ // Reapply the RemoteViews
+ contentView.reapply(this, oldEntry.content);
+ // update the contentIntent
+ final PendingIntent contentIntent = notification.notification.contentIntent;
+ if (contentIntent != null) {
+ oldEntry.content.setOnClickListener(new NotificationClicker(contentIntent,
+ notification.pkg, notification.tag, notification.id));
+ }
+ // Update the icon.
+ final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
+ notification.notification.icon, notification.notification.iconLevel,
+ notification.notification.number);
+ if (!oldEntry.icon.set(ic)) {
+ handleNotificationError(key, notification, "Couldn't update icon: " + ic);
+ return;
+ }
+ }
+ catch (RuntimeException e) {
+ // It failed to add cleanly. Log, and remove the view from the panel.
+ Slog.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
+ removeNotificationViews(key);
+ addNotificationViews(key, notification);
+ }
+ } else {
+ if (DEBUG) Slog.d(TAG, "not reusing notification for key: " + key);
+ removeNotificationViews(key);
+ addNotificationViews(key, notification);
+ }
+ // TODO: kicker; immersive mode
+ }
+
+ public void removeNotification(IBinder key) {
+ if (DEBUG) Slog.d(TAG, "removeNotification(" + key + ") // TODO");
+ removeNotificationViews(key);
+ }
+
+ public void disable(int state) {
+ /*
+ final int old = mDisabled;
+ final int diff = state ^ old;
+ mDisabled = state;
+
+ if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
+ if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
+ Slog.d(TAG, "DISABLE_EXPAND: yes");
+ animateCollapse();
+ }
+ }
+ if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+ if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+ Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
+ if (mTicking) {
+ mKicker.halt();
+ } else {
+ mNotificationIconArea.setVisibility(View.INVISIBLE);
+ }
+ } else {
+ Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
+ if (!mExpandedVisible) {
+ mNotificationIconArea.setVisibility(View.VISIBLE);
+ }
+ }
+ } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+ if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+ Slog.d(TAG, "DISABLE_NOTIFICATION_TICKER: yes");
+ mKicker.halt();
+ }
+ }
+ */
+ }
+
+ void performDisableActions(int net) {
+ /*
+ int old = mDisabled;
+ int diff = net ^ old;
+ mDisabled = net;
+
+ // act accordingly
+ if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
+ if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
+ Slog.d(TAG, "DISABLE_EXPAND: yes");
+ animateCollapse();
+ }
+ }
+ if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+ if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+ Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
+ if (mTicking) {
+ mNotificationIconArea.setVisibility(View.INVISIBLE);
+ mKicker.halt();
+ } else {
+ mNotificationIconArea.setVisibility(View.INVISIBLE);
+ }
+ } else {
+ Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
+ if (!mExpandedVisible) {
+ mNotificationIconArea.setVisibility(View.VISIBLE);
+ }
+ }
+ } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+ if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+ mKicker.halt();
+ }
+ }
+ */
+ }
+
+ private void tick(StatusBarNotification n) {
+ // Show the ticker if one is requested. Also don't do this
+ // until status bar window is attached to the window manager,
+ // because... well, what's the point otherwise? And trying to
+ // run a ticker without being attached will crash!
+ if (n.notification.tickerText != null && mStatusBarView.getWindowToken() != null) {
+ if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS
+ | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
+ mKicker.addEntry(n);
+ }
+ }
+ }
+
+ private class KickerController {
+ View mView;
+ ImageView mKickerIcon;
+ TextSwitcher mKickerText;
+
+ public KickerController(Context context, View sb) {
+ mView = sb.findViewById(R.id.ticker);
+ mKickerIcon = (ImageView) mView.findViewById(R.id.tickerIcon);
+ mKickerText = (TextSwitcher) mView.findViewById(R.id.tickerText);
+ }
+
+ public void halt() {
+ tickerHalting();
+ }
+
+ public void addEntry(StatusBarNotification n) {
+ mKickerIcon.setImageResource(n.notification.icon);
+ mKickerText.setCurrentText(n.notification.tickerText);
+ tickerStarting();
+ }
+
+ public void tickerStarting() {
+ mTicking = true;
+ mIconLayout.setVisibility(View.GONE);
+ mKickerView.setVisibility(View.VISIBLE);
+ }
+
+ public void tickerDone() {
+ mIconLayout.setVisibility(View.VISIBLE);
+ mKickerView.setVisibility(View.GONE);
+ mTicking = false;
+ }
+
+ public void tickerHalting() {
+ mIconLayout.setVisibility(View.VISIBLE);
+ mKickerView.setVisibility(View.GONE);
+ mTicking = false;
+ }
+ }
+
+ public void animateExpand() {
+ mHandler.removeMessages(H.MSG_OPEN_NOTIFICATION_PANEL);
+ mHandler.sendEmptyMessage(H.MSG_OPEN_NOTIFICATION_PANEL);
+ }
+
+ public void animateCollapse() {
+ mHandler.removeMessages(H.MSG_CLOSE_NOTIFICATION_PANEL);
+ mHandler.sendEmptyMessage(H.MSG_CLOSE_NOTIFICATION_PANEL);
+ mHandler.removeMessages(H.MSG_CLOSE_SYSTEM_PANEL);
+ mHandler.sendEmptyMessage(H.MSG_CLOSE_SYSTEM_PANEL);
+ }
+
+ public void notificationIconsClicked(View v) {
+ if (DEBUG) Slog.d(TAG, "clicked notification icons");
+ mHandler.removeMessages(H.MSG_CLOSE_SYSTEM_PANEL);
+ mHandler.sendEmptyMessage(H.MSG_CLOSE_SYSTEM_PANEL);
+
+ int msg = (mNotificationPanel.getVisibility() == View.GONE)
+ ? H.MSG_OPEN_NOTIFICATION_PANEL
+ : H.MSG_CLOSE_NOTIFICATION_PANEL;
+ mHandler.removeMessages(msg);
+ mHandler.sendEmptyMessage(msg);
+ }
+
+ public void systemInfoClicked(View v) {
+ if (DEBUG) Slog.d(TAG, "clicked system info");
+ mHandler.removeMessages(H.MSG_CLOSE_NOTIFICATION_PANEL);
+ mHandler.sendEmptyMessage(H.MSG_CLOSE_NOTIFICATION_PANEL);
+
+ int msg = (mSystemPanel.getVisibility() == View.GONE)
+ ? H.MSG_OPEN_SYSTEM_PANEL
+ : H.MSG_CLOSE_SYSTEM_PANEL;
+ mHandler.removeMessages(msg);
+ mHandler.sendEmptyMessage(msg);
+ }
+
+ /**
+ * Cancel this notification and tell the status bar service about the failure. Hold no locks.
+ */
+ void handleNotificationError(IBinder key, StatusBarNotification n, String message) {
+ removeNotification(key);
+ try {
+ mBarService.onNotificationError(n.pkg, n.tag, n.id, n.uid, n.initialPid, message);
+ } catch (RemoteException ex) {
+ // The end is nigh.
+ }
+ }
+
+ private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ try {
+ mBarService.onClearAllNotifications();
+ } catch (RemoteException ex) {
+ // system process is dead if we're here.
+ }
+ animateCollapse();
+ }
+ };
+
+ private class NotificationClicker implements View.OnClickListener {
+ private PendingIntent mIntent;
+ private String mPkg;
+ private String mTag;
+ private int mId;
+
+ NotificationClicker(PendingIntent intent, String pkg, String tag, int id) {
+ mIntent = intent;
+ mPkg = pkg;
+ mTag = tag;
+ mId = id;
+ }
+
+ public void onClick(View v) {
+ try {
+ // The intent we are sending is for the application, which
+ // won't have permission to immediately start an activity after
+ // the user switches to home. We know it is safe to do at this
+ // point, so make sure new activity switches are now allowed.
+ ActivityManagerNative.getDefault().resumeAppSwitches();
+ } catch (RemoteException e) {
+ }
+
+ if (mIntent != null) {
+ int[] pos = new int[2];
+ v.getLocationOnScreen(pos);
+ Intent overlay = new Intent();
+ overlay.setSourceBounds(
+ new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
+ try {
+ mIntent.send(TabletStatusBarService.this, 0, overlay);
+ } catch (PendingIntent.CanceledException e) {
+ // the stack trace isn't very helpful here. Just log the exception message.
+ Slog.w(TAG, "Sending contentIntent failed: " + e);
+ }
+ }
+
+ try {
+ mBarService.onNotificationClick(mPkg, mTag, mId);
+ } catch (RemoteException ex) {
+ // system process is dead if we're here.
+ }
+
+ // close the shade if it was open
+ animateCollapse();
+
+ // If this click was on the intruder alert, hide that instead
+// mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
+ }
+ }
+
+ StatusBarNotification removeNotificationViews(IBinder key) {
+ NotificationData.Entry entry = mNotns.remove(key);
+ if (entry == null) {
+ Slog.w(TAG, "removeNotification for unknown key: " + key);
+ return null;
+ }
+ // Remove the expanded view.
+ ViewGroup rowParent = (ViewGroup)entry.row.getParent();
+ if (rowParent != null) rowParent.removeView(entry.row);
+ // Remove the icon.
+// ViewGroup iconParent = (ViewGroup)entry.icon.getParent();
+// if (iconParent != null) iconParent.removeView(entry.icon);
+ refreshIcons();
+
+ return entry.notification;
+ }
+
+ StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) {
+ if (DEBUG) {
+ Slog.d(TAG, "addNotificationViews(key=" + key + ", notification=" + notification);
+ }
+ // Construct the icon.
+ final StatusBarIconView iconView = new StatusBarIconView(this,
+ notification.pkg + "/0x" + Integer.toHexString(notification.id));
+ iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+
+ final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
+ notification.notification.icon,
+ notification.notification.iconLevel,
+ notification.notification.number);
+ if (!iconView.set(ic)) {
+ handleNotificationError(key, notification, "Couldn't attach StatusBarIcon: " + ic);
+ return null;
+ }
+ // Construct the expanded view.
+ NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView);
+ if (!inflateViews(entry, mPile)) {
+ handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
+ + notification);
+ return null;
+ }
+ // Add the icon.
+ mNotns.add(entry);
+ refreshIcons();
+
+ return iconView;
+ }
+
+ private void refreshIcons() {
+ // XXX: need to implement a new limited linear layout class
+ // to avoid removing & readding everything
+
+ int N = mNotns.size();
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mIconSize, mIconSize);
+
+ if (DEBUG) {
+ Slog.d(TAG, "refreshing icons (" + N + " notifications, mIconLayout="
+ + mIconLayout + ", mPile=" + mPile);
+ }
+
+ mIconLayout.removeAllViews();
+ for (int i=0; i<4; i++) {
+ if (i>=N) break;
+ mIconLayout.addView(mNotns.get(N-i-1).icon, i, params);
+ }
+
+ mPile.removeAllViews();
+ for (int i=0; i<N; i++) {
+ mPile.addView(mNotns.get(N-i-1).row);
+ }
+ }
+
+ private boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
+ StatusBarNotification sbn = entry.notification;
+ RemoteViews remoteViews = sbn.notification.contentView;
+ if (remoteViews == null) {
+ return false;
+ }
+
+ // create the row view
+ LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ View row = inflater.inflate(R.layout.status_bar_latest_event, parent, false);
+ View vetoButton = row.findViewById(R.id.veto);
+ final String _pkg = sbn.pkg;
+ final String _tag = sbn.tag;
+ final int _id = sbn.id;
+ vetoButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ try {
+ mBarService.onNotificationClear(_pkg, _tag, _id);
+ } catch (RemoteException ex) {
+ // system process is dead if we're here.
+ }
+// animateCollapse();
+ }
+ });
+
+ // bind the click event to the content area
+ ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
+ // XXX: update to allow controls within notification views
+ content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+// content.setOnFocusChangeListener(mFocusChangeListener);
+ PendingIntent contentIntent = sbn.notification.contentIntent;
+ if (contentIntent != null) {
+ content.setOnClickListener(new NotificationClicker(contentIntent,
+ sbn.pkg, sbn.tag, sbn.id));
+ }
+
+ View expanded = null;
+ Exception exception = null;
+ try {
+ expanded = remoteViews.apply(this, content);
+ }
+ catch (RuntimeException e) {
+ exception = e;
+ }
+ if (expanded == null) {
+ String ident = sbn.pkg + "/0x" + Integer.toHexString(sbn.id);
+ Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
+ return false;
+ } else {
+ content.addView(expanded);
+ row.setDrawingCacheEnabled(true);
+ }
+
+ entry.row = row;
+ entry.content = content;
+ entry.expanded = expanded;
+
+ return true;
+ }
+}