summaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/Keyguard/res/layout/keyguard_status_view.xml3
-rw-r--r--packages/Keyguard/res/values-sw600dp-land/dimens.xml1
-rw-r--r--packages/Keyguard/res/values-sw600dp/dimens.xml2
-rw-r--r--packages/Keyguard/res/values/dimens.xml2
-rw-r--r--packages/Keyguard/res/values/strings.xml4
-rw-r--r--packages/Keyguard/res/values/styles.xml2
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java4
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java8
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java5
-rw-r--r--packages/SystemUI/AndroidManifest.xml2
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_qs_default_user.pngbin5533 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_qs_default_user.pngbin3699 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_qs_default_user.pngbin7546 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_qs_default_user.pngbin7494 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable/ic_account_circle.xml28
-rw-r--r--packages/SystemUI/res/drawable/notification_header_bg.xml2
-rw-r--r--packages/SystemUI/res/drawable/qs_panel_background.xml13
-rw-r--r--packages/SystemUI/res/layout/keyguard_bottom_area.xml3
-rw-r--r--packages/SystemUI/res/layout/qs_panel.xml5
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml7
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded_header.xml24
-rw-r--r--packages/SystemUI/res/values-sw600dp/dimens.xml4
-rw-r--r--packages/SystemUI/res/values/dimens.xml5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java262
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java324
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java186
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java158
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java128
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java218
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java16
48 files changed, 1364 insertions, 406 deletions
diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml
index f79819f..112e371 100644
--- a/packages/Keyguard/res/layout/keyguard_status_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_status_view.xml
@@ -39,13 +39,12 @@
android:id="@+id/clock_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal|top"
+ android:layout_gravity="center_horizontal"
android:textColor="@color/clock_white"
android:singleLine="true"
style="@style/widget_big_thin"
android:format12Hour="@string/keyguard_widget_12_hours_format"
android:format24Hour="@string/keyguard_widget_24_hours_format"
- android:baselineAligned="true"
android:layout_marginBottom="@dimen/bottom_text_spacing_digital" />
<include layout="@layout/keyguard_status_area" />
diff --git a/packages/Keyguard/res/values-sw600dp-land/dimens.xml b/packages/Keyguard/res/values-sw600dp-land/dimens.xml
index 5615ff7..13a6f62 100644
--- a/packages/Keyguard/res/values-sw600dp-land/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp-land/dimens.xml
@@ -26,5 +26,4 @@
<!-- Overload default clock widget parameters -->
<dimen name="widget_big_font_size">88dp</dimen>
- <dimen name="bottom_text_spacing_digital">-24dp</dimen>
</resources> \ No newline at end of file
diff --git a/packages/Keyguard/res/values-sw600dp/dimens.xml b/packages/Keyguard/res/values-sw600dp/dimens.xml
index a5e93dc..b954792 100644
--- a/packages/Keyguard/res/values-sw600dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp/dimens.xml
@@ -65,7 +65,7 @@
<!-- Overload default clock widget parameters -->
<dimen name="widget_big_font_size">96dp</dimen>
<dimen name="widget_label_font_size">16sp</dimen>
- <dimen name="bottom_text_spacing_digital">-24dp</dimen>
+ <dimen name="bottom_text_spacing_digital">-8dp</dimen>
<!-- EmergencyCarrierArea overlap - amount to overlap the emergency button and carrier text.
Should be 0 on devices with plenty of room (e.g. tablets) -->
diff --git a/packages/Keyguard/res/values/dimens.xml b/packages/Keyguard/res/values/dimens.xml
index 6224aed..3830df7 100644
--- a/packages/Keyguard/res/values/dimens.xml
+++ b/packages/Keyguard/res/values/dimens.xml
@@ -155,7 +155,7 @@
<dimen name="eca_overlap">-10dip</dimen>
<!-- Default clock parameters -->
- <dimen name="bottom_text_spacing_digital">-18dp</dimen>
+ <dimen name="bottom_text_spacing_digital">-6dp</dimen>
<dimen name="label_font_size">14dp</dimen>
<dimen name="widget_label_font_size">14sp</dimen>
<dimen name="widget_big_font_size">68dp</dimen>
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index d20b269..8cf07fa 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -97,9 +97,9 @@
<string name="keyguard_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
<!-- Time format strings for fall-back clock widget -->
- <string name="keyguard_widget_12_hours_format" translatable="false">h&#58;mm</string>
+ <string name="keyguard_widget_12_hours_format" translatable="false">h\uee01mm</string>
<!-- Time format strings for fall-back clock widget -->
- <string name="keyguard_widget_24_hours_format" translatable="false">kk&#58;mm</string>
+ <string name="keyguard_widget_24_hours_format" translatable="false">kk\uee01mm</string>
<!-- Accessibility description sent when user changes the current lock screen widget. [CHAR_LIMIT=none] -->
<string name="keyguard_accessibility_widget_changed">%1$s. Widget %2$d of %3$d.</string>
diff --git a/packages/Keyguard/res/values/styles.xml b/packages/Keyguard/res/values/styles.xml
index 5ab00d2..11142cf 100644
--- a/packages/Keyguard/res/values/styles.xml
+++ b/packages/Keyguard/res/values/styles.xml
@@ -59,8 +59,6 @@
<!-- Built-in clock widget stuff -->
<style name="widget_label">
- <item name="android:textStyle">bold</item>
- <item name="android:fontFamily">sans-serif-light</item>
<item name="android:textSize">@dimen/widget_label_font_size</item>
</style>
<style name="big_thin">
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index 2685447..d2bf30c 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -112,7 +112,9 @@ public class KeyguardHostView extends KeyguardViewBase {
}
public interface OnDismissAction {
- /* returns true if the dismiss should be deferred */
+ /**
+ * @return true if the dismiss should be deferred
+ */
boolean onDismiss();
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index ae55c4a..bef94fa 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -95,6 +95,10 @@ public class KeyguardStatusView extends GridLayout {
final boolean screenOn = KeyguardUpdateMonitor.getInstance(mContext).isScreenOn();
setEnableMarquee(screenOn);
refresh();
+
+ // Disable elegant text height because our fancy colon makes the ymin value huge for no
+ // reason.
+ mClockView.setElegantTextHeight(false);
}
protected void refresh() {
@@ -164,6 +168,10 @@ public class KeyguardStatusView extends GridLayout {
clockView24 = DateFormat.getBestDateTimePattern(locale, clockView24Skel);
+ // Use fancy colon.
+ clockView24 = clockView24.replace(':', '\uee01');
+ clockView12 = clockView12.replace(':', '\uee01');
+
cacheKey = key;
}
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
index a9206e7..48b7be9 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
@@ -237,11 +237,6 @@ public abstract class KeyguardViewBase extends FrameLayout implements SecurityCa
if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
mSecurityContainer.showPrimarySecurityScreen(false);
mSecurityContainer.onResume(KeyguardSecurityView.SCREEN_ON);
-
- // This is a an attempt to fix bug 7137389 where the device comes back on but the entire
- // layout is blank but forcing a layout causes it to reappear (e.g. with with
- // hierarchyviewer).
- requestLayout();
requestFocus();
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 6b62c25..e9cb197 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -52,6 +52,8 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
+ <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+
<!-- Physical hardware -->
<uses-permission android:name="android.permission.MANAGE_USB" />
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_default_user.png
deleted file mode 100644
index 18257e0..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_default_user.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_default_user.png
deleted file mode 100644
index a35c30d..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_default_user.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_default_user.png
deleted file mode 100644
index d14a67f..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_default_user.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_default_user.png
deleted file mode 100644
index 07f16c3..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_default_user.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_account_circle.xml b/packages/SystemUI/res/drawable/ic_account_circle.xml
new file mode 100644
index 0000000..a7e8514
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_account_circle.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="24dp"
+ android:height="24dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,5.0c1.7,0.0 3.0,1.3 3.0,3.0c0.0,1.7 -1.3,3.0 -3.0,3.0c-1.7,0.0 -3.0,-1.3 -3.0,-3.0C9.0,6.3 10.3,5.0 12.0,5.0zM12.0,19.2c-2.5,0.0 -4.7,-1.3 -6.0,-3.2c0.0,-2.0 4.0,-3.1 6.0,-3.1c2.0,0.0 6.0,1.1 6.0,3.1C16.7,17.9 14.5,19.2 12.0,19.2z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/notification_header_bg.xml b/packages/SystemUI/res/drawable/notification_header_bg.xml
index 09d0d7d..5daec20 100644
--- a/packages/SystemUI/res/drawable/notification_header_bg.xml
+++ b/packages/SystemUI/res/drawable/notification_header_bg.xml
@@ -19,13 +19,11 @@
<item android:state_pressed="true">
<shape>
<solid android:color="@color/background_color_1_press" />
- <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" />
</shape>
</item>
<item>
<shape>
<solid android:color="@color/background_color_1" />
- <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" />
</shape>
</item>
</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_panel_background.xml b/packages/SystemUI/res/drawable/qs_panel_background.xml
index c324976..a1a5362 100644
--- a/packages/SystemUI/res/drawable/qs_panel_background.xml
+++ b/packages/SystemUI/res/drawable/qs_panel_background.xml
@@ -13,11 +13,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="@dimen/notification_side_padding"
- android:insetRight="@dimen/notification_side_padding">
- <shape>
- <solid android:color="@color/system_primary_color" />
- <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" />
- </shape>
-</inset>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="@color/system_primary_color" />
+ <corners
+ android:radius="@*android:dimen/notification_quantum_rounded_rect_radius"/>
+</shape>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 2ec3766..21e5390 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -53,7 +53,8 @@
android:layout_marginBottom="100dp"
android:layout_gravity="bottom|center_horizontal"
android:textStyle="italic"
- android:textAppearance="?android:attr/textAppearanceMedium"/>
+ android:textColor="#ffffff"
+ android:textAppearance="?android:attr/textAppearanceSmall"/>
<ImageView
android:id="@+id/lock_icon"
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 85de645..398787f 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -16,11 +16,10 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/quick_settings_container"
- android:paddingLeft="@dimen/notification_side_padding"
- android:paddingRight="@dimen/notification_side_padding"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@drawable/qs_panel_background" >
+ android:background="@drawable/qs_panel_background"
+ android:elevation="2dp">
<com.android.systemui.qs.QSPanel
android:id="@+id/quick_settings_panel"
android:background="#0000"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 2ec9935..cde83bf 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -59,8 +59,8 @@
android:id="@+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:visibility="invisible"
android:scrollbars="none"
+ android:overScrollMode="never"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
@@ -70,7 +70,9 @@
layout="@layout/qs_panel"
android:layout_marginTop="@dimen/status_bar_header_height_expanded"
android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/notification_side_padding"
+ android:layout_marginRight="@dimen/notification_side_padding"/>
<!-- A view to reserve space for the collapsed stack -->
<View
@@ -79,7 +81,6 @@
</LinearLayout>
</com.android.systemui.statusbar.phone.ObservableScrollView>
-
<com.android.systemui.statusbar.stack.NotificationStackScrollLayout
android:id="@+id/notification_stack_scroller"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 89fa988..dfc3b22 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -25,7 +25,7 @@
android:paddingStart="@dimen/notification_side_padding"
android:paddingEnd="@dimen/notification_side_padding"
android:baselineAligned="false"
- android:elevation="10dp"
+ android:elevation="4dp"
>
<View
@@ -65,22 +65,13 @@
/>
</RelativeLayout>
- <com.android.keyguard.CarrierText
- android:id="@+id/keyguard_carrier_text"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/status_bar_header_height_keyguard"
- android:layout_marginLeft="8dp"
- android:gravity="center_vertical"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
<com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch"
android:layout_width="40dp"
android:layout_height="@dimen/status_bar_header_height"
android:layout_alignParentEnd="true"
android:background="@null"
android:scaleType="centerInside"
- android:padding="6dp"
+ android:padding="8dp"
/>
<ImageButton android:id="@+id/settings_button"
@@ -98,6 +89,17 @@
android:layout_marginEnd="4dp"
/>
+ <com.android.keyguard.CarrierText
+ android:id="@+id/keyguard_carrier_text"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/status_bar_header_height_keyguard"
+ android:layout_marginLeft="8dp"
+ android:layout_toStartOf="@id/system_icons_container"
+ android:gravity="center_vertical"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="#ffffff" />
+
<include
layout="@layout/quick_settings_brightness_dialog"
android:id="@+id/brightness_container"
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 22815f3..5750faa 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -57,6 +57,6 @@
<!-- The margin between the clock and the notifications on Keyguard. See
keyguard_clock_height_fraction_* for the difference between min and max.-->
- <dimen name="keyguard_clock_notifications_margin_min">32dp</dimen>
- <dimen name="keyguard_clock_notifications_margin_max">32dp</dimen>
+ <dimen name="keyguard_clock_notifications_margin_min">36dp</dimen>
+ <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c209434..bf0cb68 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -196,6 +196,9 @@
<dimen name="qs_dual_tile_height">109dp</dimen>
<dimen name="qs_dual_tile_padding">12dp</dimen>
+ <!-- How far the expanded QS panel peeks from the header in collapsed state. -->
+ <dimen name="qs_peek_height">8dp</dimen>
+
<!-- used by DessertCase -->
<dimen name="dessert_case_cell_size">192dp</dimen>
@@ -246,7 +249,7 @@
<dimen name="notification_side_padding">8dp</dimen>
<!-- Z distance between notifications if they are in the stack -->
- <dimen name="z_distance_between_notifications">2dp</dimen>
+ <dimen name="z_distance_between_notifications">1dp</dimen>
<!-- The padding between the individual notification cards when dimmed. -->
<dimen name="notification_padding_dimmed">0dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index c0f9bf2..191bac9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -20,6 +20,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.net.ConnectivityManager;
import android.provider.Settings.Global;
import com.android.systemui.R;
@@ -52,10 +53,9 @@ public class AirplaneModeTile extends QSTile<QSTile.BooleanState> {
}
private void setEnabled(boolean enabled) {
- mSetting.setValue(enabled ? 1 : 0);
- final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- intent.putExtra("state", enabled);
- mContext.sendBroadcast(intent);
+ final ConnectivityManager mgr =
+ (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ mgr.setAirplaneMode(enabled);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index ac16164..e3dac4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -21,15 +21,25 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.RectF;
+import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
import android.view.animation.PathInterpolator;
-
import com.android.systemui.R;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
/**
* Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
@@ -41,6 +51,36 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private static final int BACKGROUND_ANIMATION_LENGTH_MS = 220;
private static final int ACTIVATE_ANIMATION_LENGTH = 220;
+ /**
+ * The amount of width, which is kept in the end when performing a disappear animation (also
+ * the amount from which the horizontal appearing begins)
+ */
+ private static final float HORIZONTAL_COLLAPSED_REST_PARTIAL = 0.05f;
+
+ /**
+ * At which point from [0,1] does the horizontal collapse animation end (or start when
+ * expanding)? 1.0 meaning that it ends immediately and 0.0 that it is continuously animated.
+ */
+ private static final float HORIZONTAL_ANIMATION_END = 0.2f;
+
+ /**
+ * At which point from [0,1] does the alpha animation end (or start when
+ * expanding)? 1.0 meaning that it ends immediately and 0.0 that it is continuously animated.
+ */
+ private static final float ALPHA_ANIMATION_END = 0.0f;
+
+ /**
+ * At which point from [0,1] does the horizontal collapse animation start (or start when
+ * expanding)? 1.0 meaning that it starts immediately and 0.0 that it is animated at all.
+ */
+ private static final float HORIZONTAL_ANIMATION_START = 1.0f;
+
+ /**
+ * At which point from [0,1] does the vertical collapse animation start (or end when
+ * expanding) 1.0 meaning that it starts immediately and 0.0 that it is animated at all.
+ */
+ private static final float VERTICAL_ANIMATION_START = 1.0f;
+
private static final Interpolator ACTIVATE_INVERSE_INTERPOLATOR
= new PathInterpolator(0.6f, 0, 0.5f, 1);
private static final Interpolator ACTIVATE_INVERSE_ALPHA_INTERPOLATOR
@@ -53,6 +93,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private int mBgTint = 0;
private int mDimmedBgTint = 0;
+ private final int mRoundedRectCornerRadius;
/**
* Flag to indicate that the notification has been touched once and the second touch will
@@ -66,22 +107,41 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private OnActivatedListener mOnActivatedListener;
- private Interpolator mLinearOutSlowInInterpolator;
- private Interpolator mFastOutSlowInInterpolator;
+ private final Interpolator mLinearOutSlowInInterpolator;
+ private final Interpolator mFastOutSlowInInterpolator;
+ private final Interpolator mSlowOutFastInInterpolator;
+ private final Interpolator mSlowOutLinearInInterpolator;
+ private final Interpolator mLinearInterpolator;
+ private Interpolator mCurrentAppearInterpolator;
+ private Interpolator mCurrentAlphaInterpolator;
private NotificationBackgroundView mBackgroundNormal;
private NotificationBackgroundView mBackgroundDimmed;
private ObjectAnimator mBackgroundAnimator;
+ private RectF mAppearAnimationRect = new RectF();
+ private PorterDuffColorFilter mAppearAnimationFilter;
+ private float mAnimationTranslationY;
+ private boolean mDrawingAppearAnimation;
+ private Paint mAppearPaint = new Paint();
+ private ValueAnimator mAppearAnimator;
+ private float mAppearAnimationFraction = -1.0f;
+ private float mAppearAnimationTranslation;
public ActivatableNotificationView(Context context, AttributeSet attrs) {
super(context, attrs);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mFastOutSlowInInterpolator =
AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
+ mSlowOutFastInInterpolator = new PathInterpolator(0.8f, 0.0f, 0.6f, 1.0f);
mLinearOutSlowInInterpolator =
AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
+ mSlowOutLinearInInterpolator = new PathInterpolator(0.8f, 0.0f, 1.0f, 1.0f);
+ mLinearInterpolator = new LinearInterpolator();
setClipChildren(false);
setClipToPadding(false);
+ mAppearAnimationFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
+ mRoundedRectCornerRadius = getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_quantum_rounded_rect_radius);
}
@Override
@@ -316,6 +376,202 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
mBackgroundDimmed.setClipTopAmount(clipTopAmount);
}
+ @Override
+ public void performRemoveAnimation(float translationDirection, Runnable onFinishedRunnable) {
+ enableAppearDrawing(true);
+ if (mDrawingAppearAnimation) {
+ startAppearAnimation(false /* isAppearing */, translationDirection,
+ 0, onFinishedRunnable);
+ }
+ }
+
+ @Override
+ public void performAddAnimation(long delay) {
+ enableAppearDrawing(true);
+ if (mDrawingAppearAnimation) {
+ startAppearAnimation(true /* isAppearing */, -1.0f, delay, null);
+ }
+ }
+
+ private void startAppearAnimation(boolean isAppearing,
+ float translationDirection, long delay, final Runnable onFinishedRunnable) {
+ if (mAppearAnimator != null) {
+ mAppearAnimator.cancel();
+ }
+ mAnimationTranslationY = translationDirection * mActualHeight;
+ if (mAppearAnimationFraction == -1.0f) {
+ // not initialized yet, we start anew
+ if (isAppearing) {
+ mAppearAnimationFraction = 0.0f;
+ mAppearAnimationTranslation = mAnimationTranslationY;
+ } else {
+ mAppearAnimationFraction = 1.0f;
+ mAppearAnimationTranslation = 0;
+ }
+ }
+
+ float targetValue;
+ if (isAppearing) {
+ mCurrentAppearInterpolator = mSlowOutFastInInterpolator;
+ mCurrentAlphaInterpolator = mLinearOutSlowInInterpolator;
+ targetValue = 1.0f;
+ } else {
+ mCurrentAppearInterpolator = mFastOutSlowInInterpolator;
+ mCurrentAlphaInterpolator = mSlowOutLinearInInterpolator;
+ targetValue = 0.0f;
+ }
+ mAppearAnimator = ValueAnimator.ofFloat(mAppearAnimationFraction,
+ targetValue);
+ mAppearAnimator.setInterpolator(mLinearInterpolator);
+ mAppearAnimator.setDuration(
+ (long) (StackStateAnimator.ANIMATION_DURATION_APPEAR_DISAPPEAR
+ * Math.abs(mAppearAnimationFraction - targetValue)));
+ mAppearAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mAppearAnimationFraction = (float) animation.getAnimatedValue();
+ updateAppearAnimationAlpha();
+ updateAppearRect();
+ invalidate();
+ }
+ });
+ if (delay > 0) {
+ // we need to apply the initial state already to avoid drawn frames in the wrong state
+ updateAppearAnimationAlpha();
+ updateAppearRect();
+ mAppearAnimator.setStartDelay(delay);
+ }
+ mAppearAnimator.addListener(new AnimatorListenerAdapter() {
+ private boolean mWasCancelled;
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (onFinishedRunnable != null) {
+ onFinishedRunnable.run();
+ }
+ if (!mWasCancelled) {
+ mAppearAnimationFraction = -1;
+ setOutlineRect(null);
+ enableAppearDrawing(false);
+ }
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mWasCancelled = false;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mWasCancelled = true;
+ }
+ });
+ mAppearAnimator.start();
+ }
+
+ private void updateAppearRect() {
+ float inverseFraction = (1.0f - mAppearAnimationFraction);
+ float translationFraction = mCurrentAppearInterpolator.getInterpolation(inverseFraction);
+ float translateYTotalAmount = translationFraction * mAnimationTranslationY;
+ mAppearAnimationTranslation = translateYTotalAmount;
+
+ // handle width animation
+ float widthFraction = (inverseFraction - (1.0f - HORIZONTAL_ANIMATION_START))
+ / (HORIZONTAL_ANIMATION_START - HORIZONTAL_ANIMATION_END);
+ widthFraction = Math.min(1.0f, Math.max(0.0f, widthFraction));
+ widthFraction = mCurrentAppearInterpolator.getInterpolation(widthFraction);
+ float left = (getWidth() * (0.5f - HORIZONTAL_COLLAPSED_REST_PARTIAL / 2.0f) *
+ widthFraction);
+ float right = getWidth() - left;
+
+ // handle top animation
+ float heightFraction = (inverseFraction - (1.0f - VERTICAL_ANIMATION_START)) /
+ VERTICAL_ANIMATION_START;
+ heightFraction = Math.max(0.0f, heightFraction);
+ heightFraction = mCurrentAppearInterpolator.getInterpolation(heightFraction);
+
+ float top;
+ float bottom;
+ if (mAnimationTranslationY > 0.0f) {
+ bottom = mActualHeight - heightFraction * mAnimationTranslationY * 0.1f
+ - translateYTotalAmount;
+ top = bottom * heightFraction;
+ } else {
+ top = heightFraction * (mActualHeight + mAnimationTranslationY) * 0.1f -
+ translateYTotalAmount;
+ bottom = mActualHeight * (1 - heightFraction) + top * heightFraction;
+ }
+ mAppearAnimationRect.set(left, top, right, bottom);
+ setOutlineRect(left, top + mAppearAnimationTranslation, right,
+ bottom + mAppearAnimationTranslation);
+ }
+
+ private void updateAppearAnimationAlpha() {
+ int backgroundColor = getBackgroundColor();
+ if (backgroundColor != -1) {
+ float contentAlphaProgress = mAppearAnimationFraction;
+ contentAlphaProgress = contentAlphaProgress / (1.0f - ALPHA_ANIMATION_END);
+ contentAlphaProgress = Math.min(1.0f, contentAlphaProgress);
+ contentAlphaProgress = mCurrentAlphaInterpolator.getInterpolation(contentAlphaProgress);
+ int sourceColor = Color.argb((int) (255 * (1.0f - contentAlphaProgress)),
+ Color.red(backgroundColor), Color.green(backgroundColor),
+ Color.blue(backgroundColor));
+ mAppearAnimationFilter.setColor(sourceColor);
+ mAppearPaint.setColorFilter(mAppearAnimationFilter);
+ }
+ }
+
+ private int getBackgroundColor() {
+ // TODO: get real color
+ return 0xfffafafa;
+ }
+
+ /**
+ * When we draw the appear animation, we render the view in a bitmap and render this bitmap
+ * as a shader of a rect. This call creates the Bitmap and switches the drawing mode,
+ * such that the normal drawing of the views does not happen anymore.
+ *
+ * @param enable Should it be enabled.
+ */
+ private void enableAppearDrawing(boolean enable) {
+ if (enable != mDrawingAppearAnimation) {
+ if (enable) {
+ if (getWidth() == 0 || getActualHeight() == 0) {
+ // TODO: This should not happen, but it can during expansion. Needs
+ // investigation
+ return;
+ }
+ Bitmap bitmap = Bitmap.createBitmap(getWidth(), getActualHeight(),
+ Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ draw(canvas);
+ mAppearPaint.setShader(new BitmapShader(bitmap, Shader.TileMode.CLAMP,
+ Shader.TileMode.CLAMP));
+ } else {
+ mAppearPaint.setShader(null);
+ }
+ mDrawingAppearAnimation = enable;
+ invalidate();
+ }
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ if (!mDrawingAppearAnimation) {
+ super.dispatchDraw(canvas);
+ } else {
+ drawAppearRect(canvas);
+ }
+ }
+
+ private void drawAppearRect(Canvas canvas) {
+ canvas.save();
+ canvas.translate(0, mAppearAnimationTranslation);
+ canvas.drawRoundRect(mAppearAnimationRect, mRoundedRectCornerRadius,
+ mRoundedRectCornerRadius, mAppearPaint);
+ canvas.restore();
+ }
+
public void setOnActivatedListener(OnActivatedListener onActivatedListener) {
mOnActivatedListener = onActivatedListener;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 457d32e..f4db625 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -22,6 +22,7 @@ import android.app.Notification;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -46,6 +47,7 @@ import android.os.UserManager;
import android.provider.Settings;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.Log;
@@ -79,13 +81,17 @@ import com.android.systemui.statusbar.phone.KeyguardTouchDelegate;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Locale;
+import static com.android.keyguard.KeyguardHostView.OnDismissAction;
+
public abstract class BaseStatusBar extends SystemUI implements
CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener {
public static final String TAG = "StatusBar";
public static final boolean DEBUG = false;
public static final boolean MULTIUSER_DEBUG = false;
+ private static final boolean USE_NOTIFICATION_LISTENER = false;
protected static final int MSG_SHOW_RECENT_APPS = 1019;
protected static final int MSG_HIDE_RECENT_APPS = 1020;
@@ -158,6 +164,7 @@ public abstract class BaseStatusBar extends SystemUI implements
protected WindowManager mWindowManager;
protected IWindowManager mWindowManagerService;
+
protected abstract void refreshLayout(int layoutDirection);
protected Display mDisplay;
@@ -208,33 +215,47 @@ public abstract class BaseStatusBar extends SystemUI implements
private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
@Override
- public boolean onClickHandler(View view, PendingIntent pendingIntent, Intent fillInIntent) {
+ public boolean onClickHandler(
+ final View view, final PendingIntent pendingIntent, final Intent fillInIntent) {
if (DEBUG) {
Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
}
final boolean isActivity = pendingIntent.isActivity();
if (isActivity) {
- 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();
- // Also, notifications can be launched from the lock screen,
- // so dismiss the lock screen when the activity starts.
- ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
- } catch (RemoteException e) {
- }
- }
+ startNotificationActivity(new OnDismissAction() {
+ @Override
+ public boolean onDismiss() {
+ 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();
+ // Also, notifications can be launched from the lock screen,
+ // so dismiss the lock screen when the activity starts.
+ ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+ } catch (RemoteException e) {
+ }
- boolean handled = super.onClickHandler(view, pendingIntent, fillInIntent);
+ boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent);
- if (isActivity && handled) {
- // close the shade if it was open
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
- visibilityChanged(false);
+ // close the shade if it was open
+ if (handled) {
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+ visibilityChanged(false);
+ }
+ return handled; // Wait for activity start.
+ }
+ });
+ return true;
+ } else {
+ return super.onClickHandler(view, pendingIntent, fillInIntent);
}
- return handled;
+ }
+
+ private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
+ Intent fillInIntent) {
+ return super.onClickHandler(view, pendingIntent, fillInIntent);
}
};
@@ -253,6 +274,49 @@ public abstract class BaseStatusBar extends SystemUI implements
}
};
+ private final NotificationListenerService mNotificationListener =
+ new NotificationListenerService() {
+ @Override
+ public void onListenerConnected() {
+ if (DEBUG) Log.d(TAG, "onListenerConnected");
+ final StatusBarNotification[] notifications = getActiveNotifications();
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ for (StatusBarNotification sbn : notifications) {
+ addNotificationInternal(sbn);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onNotificationPosted(final StatusBarNotification sbn) {
+ if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mNotificationData.findByKey(sbn.getKey()) != null) {
+ updateNotificationInternal(sbn);
+ } else {
+ addNotificationInternal(sbn);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onNotificationRemoved(final StatusBarNotification sbn) {
+ if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ removeNotificationInternal(sbn.getKey());
+ }
+ });
+ }
+ };
+
private void updateCurrentProfilesCache() {
synchronized (mCurrentProfiles) {
mCurrentProfiles.clear();
@@ -299,14 +363,13 @@ public abstract class BaseStatusBar extends SystemUI implements
// Connect in to the status bar manager service
StatusBarIconList iconList = new StatusBarIconList();
- ArrayList<IBinder> notificationKeys = new ArrayList<IBinder>();
ArrayList<StatusBarNotification> notifications = new ArrayList<StatusBarNotification>();
mCommandQueue = new CommandQueue(this, iconList);
int[] switches = new int[8];
ArrayList<IBinder> binders = new ArrayList<IBinder>();
try {
- mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications,
+ mBarService.registerStatusBar(mCommandQueue, iconList, notifications,
switches, binders);
} catch (RemoteException ex) {
// If the system process isn't there we're doomed anyway.
@@ -332,17 +395,23 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
- // Set up the initial notification state
- N = notificationKeys.size();
- if (N == notifications.size()) {
- for (int i=0; i<N; i++) {
- addNotification(notificationKeys.get(i), notifications.get(i));
+ // Set up the initial notification state.
+ if (USE_NOTIFICATION_LISTENER) {
+ try {
+ mNotificationListener.registerAsSystemService(
+ new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
+ UserHandle.USER_ALL);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to register notification listener", e);
}
} else {
- Log.wtf(TAG, "Notification list length mismatch: keys=" + N
- + " notifications=" + notifications.size());
+ N = notifications.size();
+ for (int i=0; i<N; i++) {
+ addNotification(notifications.get(i));
+ }
}
+
if (DEBUG) {
Log.d(TAG, String.format(
"init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
@@ -381,6 +450,14 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
+ /**
+ * Takes the necessary steps to prepare the status bar for starting an activity, then starts it.
+ * @param action A dismiss action that is called if it's safe to start the activity.
+ */
+ protected void startNotificationActivity(OnDismissAction action) {
+ action.onDismiss();
+ }
+
@Override
protected void onConfigurationChanged(Configuration newConfig) {
final Locale locale = mContext.getResources().getConfiguration().locale;
@@ -946,47 +1023,55 @@ public abstract class BaseStatusBar extends SystemUI implements
mIsHeadsUp = forHun;
}
- 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();
- // Also, notifications can be launched from the lock screen,
- // so dismiss the lock screen when the activity starts.
- ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
- } catch (RemoteException e) {
- }
+ public void onClick(final View v) {
+ startNotificationActivity(new OnDismissAction() {
+ public boolean onDismiss() {
+ 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();
+ // Also, notifications can be launched from the lock screen,
+ // so dismiss the lock screen when the activity starts.
+ ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+ } 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(mContext, 0, overlay);
- } catch (PendingIntent.CanceledException e) {
- // the stack trace isn't very helpful here. Just log the exception message.
- Log.w(TAG, "Sending contentIntent failed: " + e);
- }
+ boolean sent = false;
+ 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(mContext, 0, overlay);
+ sent = true;
+ } catch (PendingIntent.CanceledException e) {
+ // the stack trace isn't very helpful here.
+ // Just log the exception message.
+ Log.w(TAG, "Sending contentIntent failed: " + e);
+ }
+ }
- KeyguardTouchDelegate.getInstance(mContext).dismiss();
- }
+ try {
+ if (mIsHeadsUp) {
+ mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
+ }
+ mBarService.onNotificationClick(mNotificationKey);
+ } catch (RemoteException ex) {
+ // system process is dead if we're here.
+ }
- try {
- if (mIsHeadsUp) {
- mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
- }
- mBarService.onNotificationClick(mNotificationKey);
- } catch (RemoteException ex) {
- // system process is dead if we're here.
- }
+ // close the shade if it was open
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+ visibilityChanged(false);
- // close the shade if it was open
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
- visibilityChanged(false);
+ boolean waitForActivityLaunch = sent && mIntent.isActivity();
+ return waitForActivityLaunch;
+ }
+ });
}
}
@@ -1018,8 +1103,8 @@ public abstract class BaseStatusBar extends SystemUI implements
*
* WARNING: this will call back into us. Don't hold any locks.
*/
- void handleNotificationError(IBinder key, StatusBarNotification n, String message) {
- removeNotification(key);
+ void handleNotificationError(StatusBarNotification n, String message) {
+ removeNotification(n.getKey());
try {
mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(),
n.getInitialPid(), message, n.getUserId());
@@ -1028,7 +1113,7 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
- protected StatusBarNotification removeNotificationViews(IBinder key) {
+ protected StatusBarNotification removeNotificationViews(String key) {
NotificationData.Entry entry = mNotificationData.remove(key);
if (entry == null) {
Log.w(TAG, "removeNotification for unknown key: " + key);
@@ -1039,14 +1124,14 @@ public abstract class BaseStatusBar extends SystemUI implements
if (rowParent != null) rowParent.removeView(entry.row);
updateRowStates();
updateNotificationIcons();
+ updateSpeedBump();
return entry.notification;
}
- protected NotificationData.Entry createNotificationViews(IBinder key,
- StatusBarNotification notification) {
+ protected NotificationData.Entry createNotificationViews(StatusBarNotification notification) {
if (DEBUG) {
- Log.d(TAG, "createNotificationViews(key=" + key + ", notification=" + notification);
+ Log.d(TAG, "createNotificationViews(notification=" + notification);
}
// Construct the icon.
final StatusBarIconView iconView = new StatusBarIconView(mContext,
@@ -1061,13 +1146,13 @@ public abstract class BaseStatusBar extends SystemUI implements
notification.getNotification().number,
notification.getNotification().tickerText);
if (!iconView.set(ic)) {
- handleNotificationError(key, notification, "Couldn't create icon: " + ic);
+ handleNotificationError(notification, "Couldn't create icon: " + ic);
return null;
}
// Construct the expanded view.
- NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView);
+ NotificationData.Entry entry = new NotificationData.Entry(notification, iconView);
if (!inflateViews(entry, mStackScroller)) {
- handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
+ handleNotificationError(notification, "Couldn't expand RemoteViews for: "
+ notification);
return null;
}
@@ -1083,12 +1168,26 @@ public abstract class BaseStatusBar extends SystemUI implements
if (DEBUG) {
Log.d(TAG, "addNotificationViews: added at " + pos);
}
- updateNotificationIcons();
updateRowStates();
+ updateNotificationIcons();
+ updateSpeedBump();
+ }
+
+ protected void updateSpeedBump() {
+ int n = mNotificationData.size();
+ int speedBumpIndex = -1;
+ for (int i = n-1; i >= 0; i--) {
+ NotificationData.Entry entry = mNotificationData.get(i);
+ if (entry.row.getVisibility() != View.GONE && speedBumpIndex == -1
+ && entry.row.isBelowSpeedBump() ) {
+ speedBumpIndex = n - 1 - i;
+ }
+ }
+ mStackScroller.updateSpeedBumpIndex(speedBumpIndex);
}
- private void addNotificationViews(IBinder key, StatusBarNotification notification) {
- addNotificationViews(createNotificationViews(key, notification));
+ private void addNotificationViews(StatusBarNotification notification) {
+ addNotificationViews(createNotificationViews(notification));
}
/**
@@ -1104,7 +1203,6 @@ public abstract class BaseStatusBar extends SystemUI implements
mKeyguardIconOverflowContainer.getIconsView().removeAllViews();
int n = mNotificationData.size();
int visibleNotifications = 0;
- int speedBumpIndex = -1;
boolean onKeyguard = mState == StatusBarState.KEYGUARD;
for (int i = n-1; i >= 0; i--) {
NotificationData.Entry entry = mNotificationData.get(i);
@@ -1125,17 +1223,14 @@ public abstract class BaseStatusBar extends SystemUI implements
mKeyguardIconOverflowContainer.getIconsView().addNotification(entry);
}
} else {
- if (entry.row.getVisibility() == View.GONE) {
+ boolean wasGone = entry.row.getVisibility() == View.GONE;
+ entry.row.setVisibility(View.VISIBLE);
+ if (wasGone) {
// notify the scroller of a child addition
mStackScroller.generateAddAnimation(entry.row);
}
- entry.row.setVisibility(View.VISIBLE);
visibleNotifications++;
}
- if (entry.row.getVisibility() != View.GONE && speedBumpIndex == -1
- && entry.row.isBelowSpeedBump() ) {
- speedBumpIndex = n - 1 - i;
- }
}
if (onKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) {
@@ -1143,8 +1238,6 @@ public abstract class BaseStatusBar extends SystemUI implements
} else {
mKeyguardIconOverflowContainer.setVisibility(View.GONE);
}
-
- mStackScroller.updateSpeedBumpIndex(speedBumpIndex);
}
private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
@@ -1160,7 +1253,7 @@ public abstract class BaseStatusBar extends SystemUI implements
protected abstract void haltTicker();
protected abstract void setAreThereNotifications();
protected abstract void updateNotificationIcons();
- protected abstract void tick(IBinder key, StatusBarNotification n, boolean firstTime);
+ protected abstract void tick(StatusBarNotification n, boolean firstTime);
protected abstract void updateExpandedViewPos(int expandedPosition);
protected abstract boolean shouldDisableNavbarGestures();
@@ -1168,12 +1261,37 @@ public abstract class BaseStatusBar extends SystemUI implements
return parent != null && parent.indexOfChild(entry.row) == 0;
}
- public void updateNotification(IBinder key, StatusBarNotification notification) {
- if (DEBUG) Log.d(TAG, "updateNotification(" + key + " -> " + notification + ")");
- final NotificationData.Entry oldEntry = mNotificationData.findByKey(key);
+ @Override
+ public void addNotification(StatusBarNotification notification) {
+ if (!USE_NOTIFICATION_LISTENER) {
+ addNotificationInternal(notification);
+ }
+ }
+
+ public abstract void addNotificationInternal(StatusBarNotification notification);
+
+ @Override
+ public void removeNotification(String key) {
+ if (!USE_NOTIFICATION_LISTENER) {
+ removeNotificationInternal(key);
+ }
+ }
+
+ protected abstract void removeNotificationInternal(String key);
+
+ public void updateNotification(StatusBarNotification notification) {
+ if (!USE_NOTIFICATION_LISTENER) {
+ updateNotificationInternal(notification);
+ }
+ }
+
+ public void updateNotificationInternal(StatusBarNotification notification) {
+ if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
+
+ final NotificationData.Entry oldEntry = mNotificationData.findByKey(notification.getKey());
if (oldEntry == null) {
- Log.w(TAG, "updateNotification for unknown key: " + key);
+ Log.w(TAG, "updateNotification for unknown key: " + notification.getKey());
return;
}
@@ -1244,15 +1362,15 @@ public abstract class BaseStatusBar extends SystemUI implements
boolean orderUnchanged =
notification.getNotification().when == oldNotification.getNotification().when
&& notification.getScore() == oldNotification.getScore();
- // score now encompasses/supersedes isOngoing()
+ // score now encompasses/supersedes isOngoing()
boolean updateTicker = notification.getNotification().tickerText != null
&& !TextUtils.equals(notification.getNotification().tickerText,
- oldEntry.notification.getNotification().tickerText);
+ oldEntry.notification.getNotification().tickerText);
boolean isTopAnyway = isTopNotification(rowParent, oldEntry);
if (contentsUnchanged && bigContentsUnchanged && headsUpContentsUnchanged && publicUnchanged
&& (orderUnchanged || isTopAnyway)) {
- if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
+ if (DEBUG) Log.d(TAG, "reusing notification for key: " + notification.getKey());
oldEntry.notification = notification;
try {
updateNotificationViews(oldEntry, notification);
@@ -1276,25 +1394,27 @@ public abstract class BaseStatusBar extends SystemUI implements
notification.getNotification().number,
notification.getNotification().tickerText);
if (!oldEntry.icon.set(ic)) {
- handleNotificationError(key, notification, "Couldn't update icon: " + ic);
+ handleNotificationError(notification, "Couldn't update icon: " + ic);
return;
}
updateRowStates();
+ updateSpeedBump();
}
catch (RuntimeException e) {
// It failed to add cleanly. Log, and remove the view from the panel.
Log.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
- removeNotificationViews(key);
- addNotificationViews(key, notification);
+ removeNotificationViews(notification.getKey());
+ addNotificationViews(notification);
}
} else {
- if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key);
+ if (DEBUG) Log.d(TAG, "not reusing notification for key: " + notification.getKey());
if (DEBUG) Log.d(TAG, "contents was " + (contentsUnchanged ? "unchanged" : "changed"));
if (DEBUG) Log.d(TAG, "order was " + (orderUnchanged ? "unchanged" : "changed"));
if (DEBUG) Log.d(TAG, "notification is " + (isTopAnyway ? "top" : "not top"));
- removeNotificationViews(key);
- addNotificationViews(key, notification); // will also replace the heads up
- final NotificationData.Entry newEntry = mNotificationData.findByKey(key);
+ removeNotificationViews(notification.getKey());
+ addNotificationViews(notification); // will also replace the heads up
+ final NotificationData.Entry newEntry = mNotificationData.findByKey(
+ notification.getKey());
final boolean userChangedExpansion = oldEntry.row.hasUserChangedExpansion();
if (userChangedExpansion) {
boolean userExpanded = oldEntry.row.isUserExpanded();
@@ -1314,7 +1434,7 @@ public abstract class BaseStatusBar extends SystemUI implements
// Restart the ticker if it's still running
if (updateTicker && isForCurrentUser) {
haltTicker();
- tick(key, notification, false);
+ tick(notification, false);
}
// Recalculate the position of the sliding windows and the titles.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index b4a347b..aaeadb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -21,7 +21,6 @@ import android.os.IBinder;
import android.os.Message;
import android.service.notification.StatusBarNotification;
-import com.android.internal.policy.IKeyguardShowCallback;
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIconList;
@@ -73,11 +72,6 @@ public class CommandQueue extends IStatusBar.Stub {
private Callbacks mCallbacks;
private Handler mHandler = new H();
- private class NotificationQueueEntry {
- IBinder key;
- StatusBarNotification notification;
- }
-
/**
* These methods are called back on the main thread.
*/
@@ -86,9 +80,9 @@ public class CommandQueue extends IStatusBar.Stub {
public void updateIcon(String slot, int index, int viewIndex,
StatusBarIcon old, StatusBarIcon icon);
public void removeIcon(String slot, int index, int viewIndex);
- public void addNotification(IBinder key, StatusBarNotification notification);
- public void updateNotification(IBinder key, StatusBarNotification notification);
- public void removeNotification(IBinder key);
+ public void addNotification(StatusBarNotification notification);
+ public void updateNotification(StatusBarNotification notification);
+ public void removeNotification(String key);
public void disable(int state);
public void animateExpandNotificationsPanel();
public void animateCollapsePanels(int flags);
@@ -106,7 +100,6 @@ public class CommandQueue extends IStatusBar.Stub {
public void showSearchPanel();
public void hideSearchPanel();
public void setWindowState(int window, int state);
-
}
public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
@@ -130,25 +123,21 @@ public class CommandQueue extends IStatusBar.Stub {
}
}
- public void addNotification(IBinder key, StatusBarNotification notification) {
+ @Override
+ public void addNotification(StatusBarNotification notification) {
synchronized (mList) {
- NotificationQueueEntry ne = new NotificationQueueEntry();
- ne.key = key;
- ne.notification = notification;
- mHandler.obtainMessage(MSG_ADD_NOTIFICATION, 0, 0, ne).sendToTarget();
+ mHandler.obtainMessage(MSG_ADD_NOTIFICATION, 0, 0, notification).sendToTarget();
}
}
- public void updateNotification(IBinder key, StatusBarNotification notification) {
+ @Override
+ public void updateNotification(StatusBarNotification notification) {
synchronized (mList) {
- NotificationQueueEntry ne = new NotificationQueueEntry();
- ne.key = key;
- ne.notification = notification;
- mHandler.obtainMessage(MSG_UPDATE_NOTIFICATION, 0, 0, ne).sendToTarget();
+ mHandler.obtainMessage(MSG_UPDATE_NOTIFICATION, 0, 0, notification).sendToTarget();
}
}
- public void removeNotification(IBinder key) {
+ public void removeNotification(String key) {
synchronized (mList) {
mHandler.obtainMessage(MSG_REMOVE_NOTIFICATION, 0, 0, key).sendToTarget();
}
@@ -291,17 +280,15 @@ public class CommandQueue extends IStatusBar.Stub {
break;
}
case MSG_ADD_NOTIFICATION: {
- final NotificationQueueEntry ne = (NotificationQueueEntry)msg.obj;
- mCallbacks.addNotification(ne.key, ne.notification);
+ mCallbacks.addNotification((StatusBarNotification) msg.obj);
break;
}
case MSG_UPDATE_NOTIFICATION: {
- final NotificationQueueEntry ne = (NotificationQueueEntry)msg.obj;
- mCallbacks.updateNotification(ne.key, ne.notification);
+ mCallbacks.updateNotification((StatusBarNotification) msg.obj);
break;
}
case MSG_REMOVE_NOTIFICATION: {
- mCallbacks.removeNotification((IBinder)msg.obj);
+ mCallbacks.removeNotification((String) msg.obj);
break;
}
case MSG_DISABLE:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index a42c194..843db04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -18,8 +18,8 @@ package com.android.systemui.statusbar;
import android.content.Context;
import android.graphics.Outline;
+import android.graphics.RectF;
import android.util.AttributeSet;
-import android.widget.FrameLayout;
/**
* Like {@link ExpandableView}, but setting an outline for the height and clipping.
@@ -27,9 +27,12 @@ import android.widget.FrameLayout;
public abstract class ExpandableOutlineView extends ExpandableView {
private final Outline mOutline = new Outline();
+ private boolean mCustomOutline;
+ private float mDensity;
public ExpandableOutlineView(Context context, AttributeSet attrs) {
super(context, attrs);
+ mDensity = getResources().getDisplayMetrics().density;
}
@Override
@@ -50,11 +53,37 @@ public abstract class ExpandableOutlineView extends ExpandableView {
updateOutline();
}
- private void updateOutline() {
- mOutline.setRect(0,
- mClipTopAmount,
- getWidth(),
- Math.max(mActualHeight, mClipTopAmount));
+ protected void setOutlineRect(RectF rect) {
+ if (rect != null) {
+ setOutlineRect(rect.left, rect.top, rect.right, rect.bottom);
+ } else {
+ mCustomOutline = false;
+ updateOutline();
+ }
+ }
+
+ protected void setOutlineRect(float left, float top, float right, float bottom) {
+ mCustomOutline = true;
+
+ int rectLeft = (int) left;
+ int rectTop = (int) top;
+ int rectRight = (int) right;
+ int rectBottom = (int) bottom;
+
+ // Outlines need to be at least 1 dp
+ rectBottom = (int) Math.max(top + mDensity, rectBottom);
+ rectRight = (int) Math.max(left + mDensity, rectRight);
+ mOutline.setRect(rectLeft, rectTop, rectRight, rectBottom);
setOutline(mOutline);
}
+
+ private void updateOutline() {
+ if (!mCustomOutline) {
+ mOutline.setRect(0,
+ mClipTopAmount,
+ getWidth(),
+ Math.max(mActualHeight, mClipTopAmount));
+ setOutline(mOutline);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index eaaac10..088f076 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -205,6 +205,21 @@ public abstract class ExpandableView extends FrameLayout {
}
/**
+ * Perform a remove animation on this view.
+ *
+ * @param translationDirection The direction value from [-1 ... 1] indicating in which the
+ * animation should be performed. A value of -1 means that The
+ * remove animation should be performed upwards,
+ * such that the child appears to be going away to the top. 1
+ * Should mean the opposite.
+ * @param onFinishedRunnable A runnable which should be run when the animation is finished.
+ */
+ public abstract void performRemoveAnimation(float translationDirection,
+ Runnable onFinishedRunnable);
+
+ public abstract void performAddAnimation(long delay);
+
+ /**
* A listener notifying when {@link #getActualHeight} changes.
*/
public interface OnHeightChangedListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
index 8440b9f..0555879 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
@@ -18,8 +18,6 @@ package com.android.systemui.statusbar;
import android.app.Notification;
import android.content.Context;
-import android.os.Binder;
-import android.os.IBinder;
import android.os.Process;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
@@ -33,13 +31,14 @@ import com.android.systemui.statusbar.phone.PhoneStatusBar;
public class InterceptedNotifications {
private static final String TAG = "InterceptedNotifications";
private static final String EXTRA_INTERCEPT = "android.intercept";
+ private static final String SYNTHETIC_KEY = "InterceptedNotifications.SYNTHETIC_KEY";
private final Context mContext;
private final PhoneStatusBar mBar;
- private final ArrayMap<IBinder, StatusBarNotification> mIntercepted
- = new ArrayMap<IBinder, StatusBarNotification>();
+ private final ArrayMap<String, StatusBarNotification> mIntercepted
+ = new ArrayMap<String, StatusBarNotification>();
- private Binder mSynKey;
+ private String mSynKey;
public InterceptedNotifications(Context context, PhoneStatusBar bar) {
mContext = context;
@@ -49,36 +48,35 @@ public class InterceptedNotifications {
public void releaseIntercepted() {
final int n = mIntercepted.size();
for (int i = 0; i < n; i++) {
- final IBinder key = mIntercepted.keyAt(i);
final StatusBarNotification sbn = mIntercepted.valueAt(i);
sbn.getNotification().extras.putBoolean(EXTRA_INTERCEPT, false);
- mBar.addNotification(key, sbn);
+ mBar.addNotificationInternal(sbn);
}
mIntercepted.clear();
updateSyntheticNotification();
}
- public boolean tryIntercept(IBinder key, StatusBarNotification notification) {
+ public boolean tryIntercept(StatusBarNotification notification) {
if (!notification.getNotification().extras.getBoolean(EXTRA_INTERCEPT)) return false;
if (shouldDisplayIntercepted()) return false;
- mIntercepted.put(key, notification);
+ mIntercepted.put(notification.getKey(), notification);
updateSyntheticNotification();
return true;
}
- public void remove(IBinder key) {
+ public void remove(String key) {
if (mIntercepted.remove(key) != null) {
updateSyntheticNotification();
}
}
public boolean isSyntheticEntry(Entry ent) {
- return mSynKey != null && ent.key.equals(mSynKey);
+ return ent.key.equals(SYNTHETIC_KEY);
}
- public void update(IBinder key, StatusBarNotification notification) {
- if (mIntercepted.containsKey(key)) {
- mIntercepted.put(key, notification);
+ public void update(StatusBarNotification notification) {
+ if (mIntercepted.containsKey(notification.getKey())) {
+ mIntercepted.put(notification.getKey(), notification);
}
}
@@ -90,7 +88,7 @@ public class InterceptedNotifications {
private void updateSyntheticNotification() {
if (mIntercepted.isEmpty()) {
if (mSynKey != null) {
- mBar.removeNotification(mSynKey);
+ mBar.removeNotificationInternal(mSynKey);
mSynKey = null;
}
return;
@@ -108,10 +106,10 @@ public class InterceptedNotifications {
TAG.hashCode(), TAG, Process.myUid(), Process.myPid(), 0, n,
mBar.getCurrentUserHandle());
if (mSynKey == null) {
- mSynKey = new Binder();
- mBar.addNotification(mSynKey, sbn);
+ mSynKey = sbn.getKey();
+ mBar.addNotificationInternal(sbn);
} else {
- mBar.updateNotification(mSynKey, sbn);
+ mBar.updateNotificationInternal(sbn);
}
final NotificationData.Entry entry = mBar.mNotificationData.findByKey(mSynKey);
entry.row.setOnClickListener(mSynClickListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index 3c080fe..1c2ca91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -34,7 +34,6 @@ public class NotificationBackgroundView extends View {
public NotificationBackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
- setWillNotDraw(false);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index b1a5750..5696246 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar;
-import android.os.IBinder;
import android.service.notification.StatusBarNotification;
import android.view.View;
import android.widget.ImageView;
@@ -29,7 +28,7 @@ import java.util.Comparator;
*/
public class NotificationData {
public static final class Entry {
- public IBinder key;
+ public String key;
public StatusBarNotification notification;
public StatusBarIconView icon;
public ExpandableNotificationRow row; // the outer expanded view
@@ -39,8 +38,8 @@ public class NotificationData {
public View expandedBig;
private boolean interruption;
public Entry() {}
- public Entry(IBinder key, StatusBarNotification n, StatusBarIconView ic) {
- this.key = key;
+ public Entry(StatusBarNotification n, StatusBarIconView ic) {
+ this.key = n.getKey();
this.notification = n;
this.icon = ic;
}
@@ -63,6 +62,7 @@ public class NotificationData {
interruption = true;
}
}
+
private final ArrayList<Entry> mEntries = new ArrayList<Entry>();
private final Comparator<Entry> mEntryCmp = new Comparator<Entry>() {
// sort first by score, then by when
@@ -88,9 +88,9 @@ public class NotificationData {
return mEntries.get(i);
}
- public Entry findByKey(IBinder key) {
+ public Entry findByKey(String key) {
for (Entry e : mEntries) {
- if (e.key == key) {
+ if (e.key.equals(key)) {
return e;
}
}
@@ -100,7 +100,7 @@ public class NotificationData {
public int add(Entry entry) {
int i;
int N = mEntries.size();
- for (i=0; i<N; i++) {
+ for (i = 0; i < N; i++) {
if (mEntryCmp.compare(mEntries.get(i), entry) > 0) {
break;
}
@@ -109,7 +109,7 @@ public class NotificationData {
return i;
}
- public Entry remove(IBinder key) {
+ public Entry remove(String key) {
Entry e = findByKey(key);
if (e != null) {
mEntries.remove(e);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
index 8ae503a..a84daef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
@@ -103,7 +103,11 @@ public class SpeedBumpView extends ExpandableView implements View.OnClickListene
@Override
public int getIntrinsicHeight() {
- return getActualHeight();
+ if (mCurrentAnimator != null) {
+ // expand animation is running
+ return getActualHeight();
+ }
+ return mIsExpanded ? getHeight() : mCollapsedHeight;
}
@Override
@@ -184,7 +188,7 @@ public class SpeedBumpView extends ExpandableView implements View.OnClickListene
}
public void performVisibilityAnimation(boolean nowVisible) {
- animateDivider(nowVisible);
+ animateDivider(nowVisible, null /* onFinishedRunnable */);
// Animate explanation Text
if (mIsExpanded) {
@@ -192,7 +196,14 @@ public class SpeedBumpView extends ExpandableView implements View.OnClickListene
}
}
- public void animateDivider(boolean nowVisible) {
+ /**
+ * Animate the divider to a new visibility.
+ *
+ * @param nowVisible should it now be visible
+ * @param onFinishedRunnable A runnable which should be run when the animation is
+ * finished.
+ */
+ public void animateDivider(boolean nowVisible, Runnable onFinishedRunnable) {
if (nowVisible != mDividerVisible) {
// Animate dividers
float endValue = nowVisible ? 1.0f : 0.0f;
@@ -204,7 +215,8 @@ public class SpeedBumpView extends ExpandableView implements View.OnClickListene
.scaleX(endValue)
.scaleY(endValue)
.translationX(endTranslationXLeft)
- .setInterpolator(mFastOutSlowInInterpolator);
+ .setInterpolator(mFastOutSlowInInterpolator)
+ .withEndAction(onFinishedRunnable);
mLineRight.animate()
.alpha(endValue)
.withLayer()
@@ -216,6 +228,10 @@ public class SpeedBumpView extends ExpandableView implements View.OnClickListene
// Animate dots
mDots.performVisibilityAnimation(nowVisible);
mDividerVisible = nowVisible;
+ } else {
+ if (onFinishedRunnable != null) {
+ onFinishedRunnable.run();
+ }
}
}
@@ -250,6 +266,16 @@ public class SpeedBumpView extends ExpandableView implements View.OnClickListene
}
}
+ @Override
+ public void performRemoveAnimation(float translationDirection, Runnable onFinishedRunnable) {
+ performVisibilityAnimation(false);
+ }
+
+ @Override
+ public void performAddAnimation(long delay) {
+ performVisibilityAnimation(true);
+ }
+
private void resetExplanationText() {
mExplanationText.setTranslationY(0);
mExplanationText.setVisibility(INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index d8e1766..2fa2a00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -28,6 +28,7 @@ import com.android.keyguard.R;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.keyguard.KeyguardViewMediator;
+import static com.android.keyguard.KeyguardHostView.OnDismissAction;
import static com.android.keyguard.KeyguardSecurityModel.*;
/**
@@ -64,11 +65,16 @@ public class KeyguardBouncer {
// Keyguard. If we need to authenticate, show the bouncer.
if (!mKeyguardView.dismiss()) {
mRoot.setVisibility(View.VISIBLE);
- mKeyguardView.requestFocus();
mKeyguardView.onResume();
}
}
+ public void showWithDismissAction(OnDismissAction r) {
+ ensureView();
+ mKeyguardView.setOnDismissAction(r);
+ show();
+ }
+
public void hide() {
if (mKeyguardView != null) {
mKeyguardView.cleanUp();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
new file mode 100644
index 0000000..6a83a5e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.res.Resources;
+import android.graphics.Path;
+import android.view.animation.PathInterpolator;
+
+import com.android.systemui.R;
+
+/**
+ * Utility class to calculate the clock position and top padding of notifications on Keyguard.
+ */
+public class KeyguardClockPositionAlgorithm {
+
+ private static final float SLOW_DOWN_FACTOR = 0.4f;
+
+ private static final float CLOCK_RUBBERBAND_FACTOR_MIN = 0.08f;
+ private static final float CLOCK_RUBBERBAND_FACTOR_MAX = 0.8f;
+
+ private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MIN = 1.4f;
+ private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MAX = 3.2f;
+
+ private int mClockNotificationsMarginMin;
+ private int mClockNotificationsMarginMax;
+ private float mClockYFractionMin;
+ private float mClockYFractionMax;
+ private int mMaxKeyguardNotifications;
+ private int mMaxPanelHeight;
+ private float mExpandedHeight;
+ private int mNotificationCount;
+ private int mHeight;
+ private int mKeyguardStatusHeight;
+
+ /**
+ * The number (fractional) of notifications the "more" card counts when calculating how many
+ * notifications are currently visible for the y positioning of the clock.
+ */
+ private float mMoreCardNotificationAmount;
+
+ private static final PathInterpolator sSlowDownInterpolator;
+
+ static {
+ Path path = new Path();
+ path.moveTo(0, 0);
+ path.cubicTo(0.3f, 0.875f, 0.6f, 1f, 1f, 1f);
+ sSlowDownInterpolator = new PathInterpolator(path);
+ }
+
+ /**
+ * Refreshes the dimension values.
+ */
+ public void loadDimens(Resources res) {
+ mClockNotificationsMarginMin = res.getDimensionPixelSize(
+ R.dimen.keyguard_clock_notifications_margin_min);
+ mClockNotificationsMarginMax = res.getDimensionPixelSize(
+ R.dimen.keyguard_clock_notifications_margin_max);
+ mClockYFractionMin = res.getFraction(R.fraction.keyguard_clock_y_fraction_min, 1, 1);
+ mClockYFractionMax = res.getFraction(R.fraction.keyguard_clock_y_fraction_max, 1, 1);
+ mMoreCardNotificationAmount =
+ (float) res.getDimensionPixelSize(R.dimen.notification_summary_height) /
+ res.getDimensionPixelSize(R.dimen.notification_min_height);
+ }
+
+ public void setup(int maxKeyguardNotifications, int maxPanelHeight, float expandedHeight,
+ int notificationCount, int height, int keyguardStatusHeight) {
+ mMaxKeyguardNotifications = maxKeyguardNotifications;
+ mMaxPanelHeight = maxPanelHeight;
+ mExpandedHeight = expandedHeight;
+ mNotificationCount = notificationCount;
+ mHeight = height;
+ mKeyguardStatusHeight = keyguardStatusHeight;
+ }
+
+ public void run(Result result) {
+ int y = getClockY() - mKeyguardStatusHeight/2;
+ float clockAdjustment = getClockYExpansionAdjustment();
+ float topPaddingAdjMultiplier = getTopPaddingAdjMultiplier();
+ result.stackScrollerPaddingAdjustment = (int) (clockAdjustment*topPaddingAdjMultiplier);
+ int clockNotificationsPadding = getClockNotificationsPadding()
+ + result.stackScrollerPaddingAdjustment;
+ int padding = y + clockNotificationsPadding;
+ y += clockAdjustment;
+ result.clockY = y;
+ result.stackScrollerPadding = mKeyguardStatusHeight + padding;
+ result.clockAlpha = getClockAlpha(result.stackScrollerPadding
+ - (y + mKeyguardStatusHeight));
+ }
+
+ private int getClockNotificationsPadding() {
+ float t = getNotificationAmountT();
+ t = Math.min(t, 1.0f);
+ return (int) (t * mClockNotificationsMarginMin + (1 - t) * mClockNotificationsMarginMax);
+ }
+
+ private float getClockYFraction() {
+ float t = getNotificationAmountT();
+ t = Math.min(t, 1.0f);
+ return (1 - t) * mClockYFractionMax + t * mClockYFractionMin;
+ }
+
+ private int getClockY() {
+ return (int) (getClockYFraction() * mHeight);
+ }
+
+ private float getClockYExpansionAdjustment() {
+ float rubberbandFactor = getClockYExpansionRubberbandFactor();
+ float value = (rubberbandFactor * (mMaxPanelHeight - mExpandedHeight));
+ float t = value / mMaxPanelHeight;
+ float slowedDownValue = -sSlowDownInterpolator.getInterpolation(t) * SLOW_DOWN_FACTOR
+ * mMaxPanelHeight;
+ if (mNotificationCount == 0) {
+ return (-2*value + slowedDownValue)/3;
+ } else {
+ return slowedDownValue;
+ }
+ }
+
+ private float getClockYExpansionRubberbandFactor() {
+ float t = getNotificationAmountT();
+ t = Math.min(t, 1.0f);
+ t = (float) Math.pow(t, 0.3f);
+ return (1 - t) * CLOCK_RUBBERBAND_FACTOR_MAX + t * CLOCK_RUBBERBAND_FACTOR_MIN;
+ }
+
+ private float getTopPaddingAdjMultiplier() {
+ float t = getNotificationAmountT();
+ t = Math.min(t, 1.0f);
+ return (1 - t) * CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MIN
+ + t * CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MAX;
+ }
+
+ private float getClockAlpha(int clockNotificationPadding) {
+ float t = getNotificationAmountT();
+ t = (float) Math.pow(t, 0.3f);
+ float multiplier = 1 + 2 * (1 - t);
+ float alpha = 1 + (float) clockNotificationPadding * multiplier / mKeyguardStatusHeight * 3;
+ return Math.max(0, Math.min(1, alpha));
+ }
+
+ /**
+ * @return a value from 0 to 1 depending on how many notification there are
+ */
+ private float getNotificationAmountT() {
+ return mNotificationCount
+ / (mMaxKeyguardNotifications + mMoreCardNotificationAmount);
+ }
+
+ public static class Result {
+
+ /**
+ * The y translation of the clock.
+ */
+ public int clockY;
+
+ /**
+ * The alpha value of the clock.
+ */
+ public float clockAlpha;
+
+ /**
+ * The top padding of the stack scroller, in pixels.
+ */
+ public int stackScrollerPadding;
+
+ /**
+ * The top padding adjustment of the stack scroller, in pixels. This value is used to adjust
+ * the padding, but not the overall panel size.
+ */
+ public int stackScrollerPaddingAdjustment;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 123a4f0..f5252a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.phone;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
@@ -48,6 +47,7 @@ public class NotificationPanelView extends PanelView implements
PhoneStatusBar mStatusBar;
private StatusBarHeaderView mHeader;
private View mQsContainer;
+ private View mQsPanel;
private View mKeyguardStatusView;
private ObservableScrollView mScrollView;
private View mStackScrollerContainer;
@@ -66,6 +66,7 @@ public class NotificationPanelView extends PanelView implements
*/
private boolean mIntercepting;
private boolean mQsExpanded;
+ private boolean mKeyguardShowing;
private float mInitialHeightOnTouch;
private float mInitialTouchX;
private float mInitialTouchY;
@@ -75,6 +76,7 @@ public class NotificationPanelView extends PanelView implements
private int mQsMinExpansionHeight;
private int mQsMaxExpansionHeight;
private int mMinStackHeight;
+ private int mQsPeekHeight;
private float mNotificationTranslation;
private int mStackScrollerIntrinsicPadding;
private boolean mQsExpansionEnabled = true;
@@ -82,19 +84,14 @@ public class NotificationPanelView extends PanelView implements
private FlingAnimationUtils mFlingAnimationUtils;
private int mStatusBarMinHeight;
- private int mClockNotificationsMarginMin;
- private int mClockNotificationsMarginMax;
- private float mClockYFractionMin;
- private float mClockYFractionMax;
private Interpolator mFastOutSlowInInterpolator;
private ObjectAnimator mClockAnimator;
private int mClockAnimationTarget = -1;
-
- /**
- * The number (fractional) of notifications the "more" card counts when calculating how many
- * notifications are currently visible for the y positioning of the clock.
- */
- private float mMoreCardNotificationAmount;
+ private int mTopPaddingAdjustment;
+ private KeyguardClockPositionAlgorithm mClockPositionAlgorithm =
+ new KeyguardClockPositionAlgorithm();
+ private KeyguardClockPositionAlgorithm.Result mClockPositionResult =
+ new KeyguardClockPositionAlgorithm.Result();
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -124,6 +121,7 @@ public class NotificationPanelView extends PanelView implements
mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
mStackScrollerContainer = findViewById(R.id.notification_container_parent);
mQsContainer = findViewById(R.id.quick_settings_container);
+ mQsPanel = findViewById(R.id.quick_settings_panel);
mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
mScrollView.setListener(this);
mNotificationStackScroller = (NotificationStackScrollLayout)
@@ -139,34 +137,24 @@ public class NotificationPanelView extends PanelView implements
mNotificationTopPadding = getResources().getDimensionPixelSize(
R.dimen.notifications_top_padding);
mMinStackHeight = getResources().getDimensionPixelSize(R.dimen.collapsed_stack_height);
- mClockNotificationsMarginMin = getResources().getDimensionPixelSize(
- R.dimen.keyguard_clock_notifications_margin_min);
- mClockNotificationsMarginMax = getResources().getDimensionPixelSize(
- R.dimen.keyguard_clock_notifications_margin_max);
- mClockYFractionMin =
- getResources().getFraction(R.fraction.keyguard_clock_y_fraction_min, 1, 1);
- mClockYFractionMax =
- getResources().getFraction(R.fraction.keyguard_clock_y_fraction_max, 1, 1);
- mMoreCardNotificationAmount =
- (float) getResources().getDimensionPixelSize(R.dimen.notification_summary_height) /
- getResources().getDimensionPixelSize(R.dimen.notification_min_height);
mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.4f);
mStatusBarMinHeight = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height);
+ mQsPeekHeight = getResources().getDimensionPixelSize(R.dimen.qs_peek_height);
+ mClockPositionAlgorithm.loadDimens(getResources());
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- if (!mQsExpanded) {
- positionClockAndNotifications();
- }
// Calculate quick setting heights.
- mQsMinExpansionHeight = mHeader.getCollapsedHeight();
+ mQsMinExpansionHeight = mHeader.getCollapsedHeight() + mQsPeekHeight;
mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getHeight();
- if (mQsExpansionHeight == 0) {
- mQsExpansionHeight = mQsMinExpansionHeight;
+ if (!mQsExpanded) {
+ setQsExpansion(mQsMinExpansionHeight);
+ positionClockAndNotifications();
+ mNotificationStackScroller.setStackHeight(getExpandedHeight());
}
}
@@ -177,17 +165,26 @@ public class NotificationPanelView extends PanelView implements
private void positionClockAndNotifications() {
boolean animateClock = mNotificationStackScroller.isAddOrRemoveAnimationPending();
if (mStatusBar.getBarState() != StatusBarState.KEYGUARD) {
- mStackScrollerIntrinsicPadding = mHeader.getBottom() + mNotificationTopPadding;
+ mStackScrollerIntrinsicPadding = mHeader.getBottom() + mQsPeekHeight
+ + mNotificationTopPadding;
+ mTopPaddingAdjustment = 0;
} else {
- int notificationCount = mNotificationStackScroller.getNotGoneChildCount();
- int y = getClockY(notificationCount) - mKeyguardStatusView.getHeight()/2;
- int padding = getClockNotificationsPadding(notificationCount);
+ mClockPositionAlgorithm.setup(
+ mStatusBar.getMaxKeyguardNotifications(),
+ getMaxPanelHeight(),
+ getExpandedHeight(),
+ mNotificationStackScroller.getNotGoneChildCount(),
+ getHeight(),
+ mKeyguardStatusView.getHeight());
+ mClockPositionAlgorithm.run(mClockPositionResult);
if (animateClock || mClockAnimator != null) {
- startClockAnimation(y);
+ startClockAnimation(mClockPositionResult.clockY);
} else {
- mKeyguardStatusView.setY(y);
+ mKeyguardStatusView.setY(mClockPositionResult.clockY);
}
- mStackScrollerIntrinsicPadding = y + mKeyguardStatusView.getHeight() + padding;
+ applyClockAlpha(mClockPositionResult.clockAlpha);
+ mStackScrollerIntrinsicPadding = mClockPositionResult.stackScrollerPadding;
+ mTopPaddingAdjustment = mClockPositionResult.stackScrollerPaddingAdjustment;
}
mNotificationStackScroller.setTopPadding(mStackScrollerIntrinsicPadding,
mAnimateNextTopPaddingChange || animateClock);
@@ -218,28 +215,19 @@ public class NotificationPanelView extends PanelView implements
mClockAnimationTarget = -1;
}
});
- StackStateAnimator.startInstantly(mClockAnimator);
+ mClockAnimator.start();
return true;
}
});
}
- private int getClockNotificationsPadding(int notificationCount) {
- float t = notificationCount
- / (mStatusBar.getMaxKeyguardNotifications() + mMoreCardNotificationAmount);
- t = Math.min(t, 1.0f);
- return (int) (t * mClockNotificationsMarginMin + (1 - t) * mClockNotificationsMarginMax);
- }
-
- private float getClockYFraction(int notificationCount) {
- float t = notificationCount
- / (mStatusBar.getMaxKeyguardNotifications() + mMoreCardNotificationAmount);
- t = Math.min(t, 1.0f);
- return (1 - t) * mClockYFractionMax + t * mClockYFractionMin;
- }
-
- private int getClockY(int notificationCount) {
- return (int) (getClockYFraction(notificationCount) * getHeight());
+ private void applyClockAlpha(float alpha) {
+ if (alpha != 1.0f) {
+ mKeyguardStatusView.setLayerType(LAYER_TYPE_HARDWARE, null);
+ } else {
+ mKeyguardStatusView.setLayerType(LAYER_TYPE_NONE, null);
+ }
+ mKeyguardStatusView.setAlpha(alpha);
}
public void animateToFullShade() {
@@ -366,10 +354,12 @@ public class NotificationPanelView extends PanelView implements
@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
- // Block request so we can still intercept the scrolling when QS is expanded.
- if (!mQsExpanded) {
- super.requestDisallowInterceptTouchEvent(disallowIntercept);
+ // Block request when interacting with the scroll view so we can still intercept the
+ // scrolling when QS is expanded.
+ if (mScrollView.isDispatchingTouchEvent()) {
+ return;
}
+ super.requestDisallowInterceptTouchEvent(disallowIntercept);
}
private void flingWithCurrentVelocity() {
@@ -466,31 +456,41 @@ public class NotificationPanelView extends PanelView implements
setQsExpansion(height);
}
- private void expandQs() {
- mHeader.setExpanded(true);
- mNotificationStackScroller.setEnabled(false);
- mScrollView.setVisibility(View.VISIBLE);
- mQsExpanded = true;
+ private void setQsExpanded(boolean expanded) {
+ boolean changed = mQsExpanded != expanded;
+ if (changed) {
+ mQsExpanded = expanded;
+ updateQsState();
+ }
+ }
+
+ public void setKeyguardShowing(boolean keyguardShowing) {
+ mKeyguardShowing = keyguardShowing;
+ updateQsState();
}
- private void collapseQs() {
- mHeader.setExpanded(false);
- mNotificationStackScroller.setEnabled(true);
- mScrollView.setVisibility(View.INVISIBLE);
- mQsExpanded = false;
+ private void updateQsState() {
+ mHeader.setExpanded(mQsExpanded);
+ mNotificationStackScroller.setEnabled(!mQsExpanded);
+ mQsPanel.setVisibility(mQsExpanded ? View.VISIBLE : View.INVISIBLE);
+ mQsContainer.setVisibility(mKeyguardShowing && !mQsExpanded
+ ? View.INVISIBLE
+ : View.VISIBLE);
+ mScrollView.setTouchEnabled(mQsExpanded);
}
private void setQsExpansion(float height) {
height = Math.min(Math.max(height, mQsMinExpansionHeight), mQsMaxExpansionHeight);
if (height > mQsMinExpansionHeight && !mQsExpanded) {
- expandQs();
+ setQsExpanded(true);
} else if (height <= mQsMinExpansionHeight && mQsExpanded) {
- collapseQs();
+ setQsExpanded(false);
}
mQsExpansionHeight = height;
- mHeader.setExpansion(height);
+ mHeader.setExpansion(height - mQsPeekHeight);
setQsTranslation(height);
setQsStackScrollerPadding(height);
+ mStatusBar.userActivity();
}
private void setQsTranslation(float height) {
@@ -626,7 +626,7 @@ public class NotificationPanelView extends PanelView implements
int emptyBottomMargin = mStackScrollerContainer.getHeight()
- mNotificationStackScroller.getHeight()
+ mNotificationStackScroller.getEmptyBottomMargin();
- int maxHeight = maxPanelHeight - emptyBottomMargin;
+ int maxHeight = maxPanelHeight - emptyBottomMargin - mTopPaddingAdjustment;
maxHeight = Math.max(maxHeight, mStatusBarMinHeight);
return maxHeight;
}
@@ -637,6 +637,9 @@ public class NotificationPanelView extends PanelView implements
@Override
protected void onHeightUpdated(float expandedHeight) {
+ if (!mQsExpanded) {
+ positionClockAndNotifications();
+ }
mNotificationStackScroller.setStackHeight(expandedHeight);
}
@@ -653,6 +656,23 @@ public class NotificationPanelView extends PanelView implements
}
@Override
+ protected void onOverExpansionChanged(float overExpansion) {
+ float currentOverScroll = mNotificationStackScroller.getCurrentOverScrolledPixels(true);
+ mNotificationStackScroller.setOverScrolledPixels(currentOverScroll + overExpansion
+ - mOverExpansion, true /* onTop */, false /* animate */);
+ super.onOverExpansionChanged(overExpansion);
+ }
+
+ @Override
+ protected void onTrackingStopped() {
+ super.onTrackingStopped();
+ mOverExpansion = 0.0f;
+ mNotificationStackScroller.setOverScrolledPixels(0.0f, true /* onTop */,
+ true /* animate */);
+ }
+
+
+ @Override
public void onHeightChanged(ExpandableView view) {
requestPanelHeightUpdate();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java
index ba0b66e..ea5b309 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone;
import android.content.Context;
import android.util.AttributeSet;
+import android.view.MotionEvent;
import android.view.View;
import android.widget.ScrollView;
@@ -28,6 +29,8 @@ public class ObservableScrollView extends ScrollView {
private Listener mListener;
private int mLastOverscrollAmount;
+ private boolean mDispatchingTouchEvent;
+ private boolean mTouchEnabled = true;
public ObservableScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -37,10 +40,18 @@ public class ObservableScrollView extends ScrollView {
mListener = listener;
}
+ public void setTouchEnabled(boolean touchEnabled) {
+ mTouchEnabled = touchEnabled;
+ }
+
public boolean isScrolledToBottom() {
return getScrollY() == getMaxScrollY();
}
+ public boolean isDispatchingTouchEvent() {
+ return mDispatchingTouchEvent;
+ }
+
private int getMaxScrollY() {
int scrollRange = 0;
if (getChildCount() > 0) {
@@ -52,6 +63,17 @@ public class ObservableScrollView extends ScrollView {
}
@Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (!mTouchEnabled) {
+ return false;
+ }
+ mDispatchingTouchEvent = true;
+ boolean result = super.dispatchTouchEvent(ev);
+ mDispatchingTouchEvent = false;
+ return result;
+ }
+
+ @Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (mListener != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index b6a43a7..7c1f2cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -38,6 +38,7 @@ import java.io.PrintWriter;
public class PanelView extends FrameLayout {
public static final boolean DEBUG = PanelBar.DEBUG;
public static final String TAG = PanelView.class.getSimpleName();
+ protected float mOverExpansion;
private final void logf(String fmt, Object... args) {
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -402,7 +403,12 @@ public class PanelView extends FrameLayout {
public void setExpandedHeightInternal(float h) {
float fh = getMaxPanelHeight();
- mExpandedHeight = h;
+ mExpandedHeight = Math.min(fh, h);
+ float overExpansion = h - fh;
+ overExpansion = Math.max(0, overExpansion);
+ if (overExpansion != mOverExpansion) {
+ onOverExpansionChanged(overExpansion);
+ }
if (DEBUG) {
logf("setExpansion: height=%.1f fh=%.1f tracking=%s", h, fh, mTracking ? "T" : "f");
@@ -412,6 +418,10 @@ public class PanelView extends FrameLayout {
mExpandedFraction = Math.min(1f, (fh == 0) ? 0 : h / fh);
}
+ protected void onOverExpansionChanged(float overExpansion) {
+ mOverExpansion = overExpansion;
+ }
+
protected void onHeightUpdated(float expandedHeight) {
requestLayout();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 54af2c5..28367d0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -22,6 +22,7 @@ import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.windowStateToString;
+import static com.android.keyguard.KeyguardHostView.OnDismissAction;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
@@ -1027,18 +1028,19 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return new UserHandle(mCurrentUserId);
}
- public void addNotification(IBinder key, StatusBarNotification notification) {
+ @Override
+ public void addNotificationInternal(StatusBarNotification notification) {
if (DEBUG) Log.d(TAG, "addNotification score=" + notification.getScore());
- Entry shadeEntry = createNotificationViews(key, notification);
+ Entry shadeEntry = createNotificationViews(notification);
if (shadeEntry == null) {
return;
}
- if (mZenMode != Global.ZEN_MODE_OFF && mIntercepted.tryIntercept(key, notification)) {
+ if (mZenMode != Global.ZEN_MODE_OFF && mIntercepted.tryIntercept(notification)) {
return;
}
if (mUseHeadsUp && shouldInterrupt(notification)) {
if (DEBUG) Log.d(TAG, "launching notification in heads up mode");
- Entry interruptionCandidate = new Entry(key, notification, null);
+ Entry interruptionCandidate = new Entry(notification, null);
ViewGroup holder = mHeadsUpNotificationView.getHolder();
if (inflateViewsForHeadsUp(interruptionCandidate, holder)) {
mInterruptingNotificationTime = System.currentTimeMillis();
@@ -1070,7 +1072,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// show the ticker if there isn't already a heads up
if (mInterruptingNotificationEntry == null) {
- tick(null, notification, true);
+ tick(notification, true);
}
}
addNotificationViews(shadeEntry);
@@ -1089,12 +1091,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
@Override
- public void updateNotification(IBinder key, StatusBarNotification notification) {
- super.updateNotification(key, notification);
- mIntercepted.update(key, notification);
+ public void updateNotification(StatusBarNotification notification) {
+ super.updateNotification(notification);
+ mIntercepted.update(notification);
}
- public void removeNotification(IBinder key) {
+ @Override
+ public void removeNotificationInternal(String key) {
StatusBarNotification old = removeNotificationViews(key);
if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
@@ -2019,7 +2022,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
public void setHardKeyboardStatus(boolean available, boolean enabled) {}
@Override
- protected void tick(IBinder key, StatusBarNotification n, boolean firstTime) {
+ protected void tick(StatusBarNotification n, boolean firstTime) {
// no ticking in lights-out mode
if (!areLightsOn()) return;
@@ -2344,6 +2347,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
};
+ @Override
+ protected void startNotificationActivity(OnDismissAction action) {
+ if (mStatusBarKeyguardViewManager.isShowing()) {
+ mStatusBarKeyguardViewManager.dismissWithAction(action);
+ } else {
+ action.onDismiss();
+ }
+ }
+
// SystemUIService notifies SystemBars of configuration changes, which then calls down here
@Override
protected void onConfigurationChanged(Configuration newConfig) {
@@ -2758,14 +2770,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
mKeyguardBottomArea.setVisibility(View.VISIBLE);
mHeader.setKeyguardShowing(true);
+ mNotificationPanel.setKeyguardShowing(true);
} else {
mKeyguardBottomArea.setVisibility(View.GONE);
mHeader.setKeyguardShowing(false);
+ mNotificationPanel.setKeyguardShowing(false);
}
updateStackScrollerState();
updatePublicMode();
updateRowStates();
+ updateSpeedBump();
checkBarModes();
updateNotificationIcons();
updateCarrierLabelVisibility(false);
@@ -2776,9 +2791,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
public void userActivity() {
- if (mState == StatusBarState.KEYGUARD) {
- mKeyguardViewMediatorCallback.userActivity();
- }
+ mHandler.removeCallbacks(mUserActivity);
+ mHandler.post(mUserActivity);
}
public boolean interceptMediaKey(KeyEvent event) {
@@ -2936,4 +2950,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
public void onScreenTurnedOn() {
mStackScroller.setAnimationsEnabled(true);
}
+
+ private final Runnable mUserActivity = new Runnable() {
+ @Override
+ public void run() {
+ if (mState == StatusBarState.KEYGUARD) {
+ mKeyguardViewMediatorCallback.userActivity();
+ }
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 389e725..3245f1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -38,6 +38,11 @@ import com.android.systemui.statusbar.policy.UserInfoController;
*/
public class StatusBarHeaderView extends RelativeLayout implements View.OnClickListener {
+ /**
+ * How much the header expansion gets rubberbanded while expanding the panel.
+ */
+ private static final float EXPANSION_RUBBERBAND_FACTOR = 0.35f;
+
private boolean mExpanded;
private boolean mKeyguardShowing;
@@ -128,6 +133,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
updateVisibilities();
updateSystemIconsLayoutParams();
updateBrightnessControllerState();
+ updateZTranslation();
+ updateClickTargets();
if (mQSPanel != null) {
mQSPanel.setExpanded(expanded);
}
@@ -202,18 +209,30 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
}
}
+ private void updateClickTargets() {
+ mDateTime.setClickable(mExpanded);
+ mMultiUserSwitch.setClickable(mExpanded);
+ }
+
+ private void updateZTranslation() {
+
+ // If we are on the Keyguard, we need to set our z position to zero, so we don't get
+ // shadows.
+ if (mKeyguardShowing && !mExpanded) {
+ setZ(0);
+ } else {
+ setTranslationZ(0);
+ }
+ }
+
public void setExpansion(float height) {
+ height = (height - mCollapsedHeight) * EXPANSION_RUBBERBAND_FACTOR + mCollapsedHeight;
if (height < mCollapsedHeight) {
height = mCollapsedHeight;
}
if (height > mExpandedHeight) {
height = mExpandedHeight;
}
- if (mExpanded) {
- mBackground.setTranslationY(-(mExpandedHeight - height));
- } else {
- mBackground.setTranslationY(0);
- }
setClipping(height);
}
@@ -247,14 +266,10 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
public void setKeyguardShowing(boolean keyguardShowing) {
mKeyguardShowing = keyguardShowing;
- if (keyguardShowing) {
- setZ(0);
- } else {
- setTranslationZ(0);
- }
updateHeights();
updateWidth();
updateVisibilities();
+ updateZTranslation();
}
public void setUserInfoController(UserInfoController userInfoController) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 1040c15..3849d8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -29,6 +29,8 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
+import static com.android.keyguard.KeyguardHostView.OnDismissAction;
+
/**
* Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back
* via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done,
@@ -108,6 +110,13 @@ public class StatusBarKeyguardViewManager {
updateStates();
}
+ public void dismissWithAction(OnDismissAction r) {
+ if (!mOccluded) {
+ mBouncer.showWithDismissAction(r);
+ }
+ updateStates();
+ }
+
/**
* Reset the state of the view.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
index 173af40..3ce6905 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
@@ -166,7 +166,7 @@ public final class UserInfoController {
if (rawAvatar != null) {
avatar = new BitmapDrawable(mContext.getResources(), circularClip(rawAvatar));
} else {
- avatar = mContext.getResources().getDrawable(R.drawable.ic_qs_default_user);
+ avatar = mContext.getResources().getDrawable(R.drawable.ic_account_circle);
mUseDefaultAvatar = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
index 41914ed..5e2d06b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -28,6 +28,7 @@ public class AnimationFilter {
boolean animateScale;
boolean animateHeight;
boolean animateDimmed;
+ boolean hasDelays;
public AnimationFilter animateAlpha() {
animateAlpha = true;
@@ -39,6 +40,11 @@ public class AnimationFilter {
return this;
}
+ public AnimationFilter hasDelays() {
+ hasDelays = true;
+ return this;
+ }
+
public AnimationFilter animateZ() {
animateZ = true;
return this;
@@ -79,6 +85,7 @@ public class AnimationFilter {
animateScale |= filter.animateScale;
animateHeight |= filter.animateHeight;
animateDimmed |= filter.animateDimmed;
+ hasDelays |= filter.hasDelays;
}
private void reset() {
@@ -88,5 +95,6 @@ public class AnimationFilter {
animateScale = false;
animateHeight = false;
animateDimmed = false;
+ hasDelays = false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 90f3d17..079b184 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -103,6 +103,7 @@ public class NotificationStackScrollLayout extends ViewGroup
private ArrayList<View> mChildrenToRemoveAnimated = new ArrayList<View>();
private ArrayList<View> mSnappedBackChildren = new ArrayList<View>();
private ArrayList<View> mDragAnimPendingChildren = new ArrayList<View>();
+ private ArrayList<View> mChildrenChangingPositions = new ArrayList<View>();
private ArrayList<AnimationEvent> mAnimationEvents
= new ArrayList<AnimationEvent>();
private ArrayList<View> mSwipedOutViews = new ArrayList<View>();
@@ -969,9 +970,24 @@ public class NotificationStackScrollLayout extends ViewGroup
}
/**
+ * @return The first child which has visibility unequal to GONE which is currently below the
+ * given translationY or equal to it.
+ */
+ private View getFirstChildBelowTranlsationY(float translationY) {
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ if (child.getVisibility() != View.GONE && child.getTranslationY() >= translationY) {
+ return child;
+ }
+ }
+ return null;
+ }
+
+ /**
* @return the last child which has visibility unequal to GONE
*/
- private View getLastChildNotGone() {
+ public View getLastChildNotGone() {
int childCount = getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
View child = getChildAt(i);
@@ -1094,23 +1110,41 @@ public class NotificationStackScrollLayout extends ViewGroup
@Override
protected void onViewRemoved(View child) {
super.onViewRemoved(child);
+ mStackScrollAlgorithm.notifyChildrenChanged(this);
+ if (mChildrenChangingPositions.contains(child)) {
+ // This is only a position change, don't do anything special
+ return;
+ }
((ExpandableView) child).setOnHeightChangedListener(null);
mCurrentStackScrollState.removeViewStateForView(child);
- mStackScrollAlgorithm.notifyChildrenChanged(this);
updateScrollStateForRemovedChild(child);
- generateRemoveAnimation(child);
+ boolean animationGenerated = generateRemoveAnimation(child);
+ if (animationGenerated && !mSwipedOutViews.contains(child)) {
+ // Add this view to an overlay in order to ensure that it will still be temporary
+ // drawn when removed
+ getOverlay().add(child);
+ }
}
- private void generateRemoveAnimation(View child) {
+ /**
+ * Generate a remove animation for a child view.
+ *
+ * @param child The view to generate the remove animation for.
+ * @return Whether an animation was generated.
+ */
+ private boolean generateRemoveAnimation(View child) {
if (mIsExpanded && mAnimationsEnabled) {
if (!mChildrenToAddAnimated.contains(child)) {
// Generate Animations
mChildrenToRemoveAnimated.add(child);
mNeedsAnimation = true;
+ return true;
} else {
mChildrenToAddAnimated.remove(child);
+ return false;
}
}
+ return false;
}
/**
@@ -1155,9 +1189,7 @@ public class NotificationStackScrollLayout extends ViewGroup
super.onViewAdded(child);
mStackScrollAlgorithm.notifyChildrenChanged(this);
((ExpandableView) child).setOnHeightChangedListener(this);
- if (child.getVisibility() != View.GONE) {
- generateAddAnimation(child);
- }
+ generateAddAnimation(child);
}
public void setAnimationsEnabled(boolean animationsEnabled) {
@@ -1168,10 +1200,13 @@ public class NotificationStackScrollLayout extends ViewGroup
return mNeedsAnimation
&& (!mChildrenToAddAnimated.isEmpty() || !mChildrenToRemoveAnimated.isEmpty());
}
-
+ /**
+ * Generate an animation for an added child view.
+ *
+ * @param child The view to be added.
+ */
public void generateAddAnimation(View child) {
- if (mIsExpanded && mAnimationsEnabled) {
-
+ if (mIsExpanded && mAnimationsEnabled && !mChildrenChangingPositions.contains(child)) {
// Generate Animations
mChildrenToAddAnimated.add(child);
mNeedsAnimation = true;
@@ -1186,9 +1221,10 @@ public class NotificationStackScrollLayout extends ViewGroup
*/
public void changeViewPosition(View child, int newIndex) {
if (child != null && child.getParent() == this) {
+ mChildrenChangingPositions.add(child);
removeView(child);
addView(child, newIndex);
- // TODO: handle events
+ mNeedsAnimation = true;
}
}
@@ -1197,16 +1233,18 @@ public class NotificationStackScrollLayout extends ViewGroup
generateChildHierarchyEvents();
mNeedsAnimation = false;
}
- if (!mAnimationEvents.isEmpty()) {
+ if (!mAnimationEvents.isEmpty() || isCurrentlyAnimating()) {
mStateAnimator.startAnimationForEvents(mAnimationEvents, mCurrentStackScrollState);
+ mAnimationEvents.clear();
} else {
applyCurrentState();
}
}
private void generateChildHierarchyEvents() {
- generateChildAdditionEvents();
generateChildRemovalEvents();
+ generateChildAdditionEvents();
+ generatePositionChangeEvents();
generateSnapBackEvents();
generateDragEvents();
generateTopPaddingEvent();
@@ -1237,12 +1275,24 @@ public class NotificationStackScrollLayout extends ViewGroup
int animationType = childWasSwipedOut
? AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT
: AnimationEvent.ANIMATION_TYPE_REMOVE;
- mAnimationEvents.add(new AnimationEvent(child, animationType));
+ AnimationEvent event = new AnimationEvent(child, animationType);
+
+ // we need to know the view after this one
+ event.viewAfterChangingView = getFirstChildBelowTranlsationY(child.getTranslationY());
+ mAnimationEvents.add(event);
}
mSwipedOutViews.clear();
mChildrenToRemoveAnimated.clear();
}
+ private void generatePositionChangeEvents() {
+ for (View child : mChildrenChangingPositions) {
+ mAnimationEvents.add(new AnimationEvent(child,
+ AnimationEvent.ANIMATION_TYPE_CHANGE_POSITION));
+ }
+ mChildrenChangingPositions.clear();
+ }
+
private void generateChildAdditionEvents() {
for (View child : mChildrenToAddAnimated) {
mAnimationEvents.add(new AnimationEvent(child,
@@ -1467,7 +1517,6 @@ public class NotificationStackScrollLayout extends ViewGroup
public void onChildAnimationFinished() {
requestChildrenUpdate();
- mAnimationEvents.clear();
}
/**
@@ -1513,9 +1562,9 @@ public class NotificationStackScrollLayout extends ViewGroup
}
private void updateSpeedBump(boolean visible) {
- int newVisibility = visible ? VISIBLE : GONE;
- int oldVisibility = mSpeedBumpView.getVisibility();
- if (newVisibility != oldVisibility) {
+ boolean notGoneBefore = mSpeedBumpView.getVisibility() != GONE;
+ if (visible != notGoneBefore) {
+ int newVisibility = visible ? VISIBLE : GONE;
mSpeedBumpView.setVisibility(newVisibility);
if (visible) {
mSpeedBumpView.collapse();
@@ -1551,21 +1600,24 @@ public class NotificationStackScrollLayout extends ViewGroup
.animateAlpha()
.animateHeight()
.animateY()
- .animateZ(),
+ .animateZ()
+ .hasDelays(),
// ANIMATION_TYPE_REMOVE
new AnimationFilter()
.animateAlpha()
.animateHeight()
.animateY()
- .animateZ(),
+ .animateZ()
+ .hasDelays(),
// ANIMATION_TYPE_REMOVE_SWIPED_OUT
new AnimationFilter()
.animateAlpha()
.animateHeight()
.animateY()
- .animateZ(),
+ .animateZ()
+ .hasDelays(),
// ANIMATION_TYPE_TOP_PADDING_CHANGED
new AnimationFilter()
@@ -1593,16 +1645,23 @@ public class NotificationStackScrollLayout extends ViewGroup
new AnimationFilter()
.animateY()
.animateScale()
- .animateDimmed()
+ .animateDimmed(),
+
+ // ANIMATION_TYPE_CHANGE_POSITION
+ new AnimationFilter()
+ .animateAlpha()
+ .animateHeight()
+ .animateY()
+ .animateZ()
};
static int[] LENGTHS = new int[] {
// ANIMATION_TYPE_ADD
- StackStateAnimator.ANIMATION_DURATION_STANDARD,
+ StackStateAnimator.ANIMATION_DURATION_APPEAR_DISAPPEAR,
// ANIMATION_TYPE_REMOVE
- StackStateAnimator.ANIMATION_DURATION_STANDARD,
+ StackStateAnimator.ANIMATION_DURATION_APPEAR_DISAPPEAR,
// ANIMATION_TYPE_REMOVE_SWIPED_OUT
StackStateAnimator.ANIMATION_DURATION_STANDARD,
@@ -1621,22 +1680,27 @@ public class NotificationStackScrollLayout extends ViewGroup
// ANIMATION_TYPE_DIMMED
StackStateAnimator.ANIMATION_DURATION_DIMMED_ACTIVATED,
+
+ // ANIMATION_TYPE_CHANGE_POSITION
+ StackStateAnimator.ANIMATION_DURATION_STANDARD,
};
- static int ANIMATION_TYPE_ADD = 0;
- static int ANIMATION_TYPE_REMOVE = 1;
- static int ANIMATION_TYPE_REMOVE_SWIPED_OUT = 2;
- static int ANIMATION_TYPE_TOP_PADDING_CHANGED = 3;
- static int ANIMATION_TYPE_START_DRAG = 4;
- static int ANIMATION_TYPE_SNAP_BACK = 5;
- static int ANIMATION_TYPE_ACTIVATED_CHILD = 6;
- static int ANIMATION_TYPE_DIMMED = 7;
+ static final int ANIMATION_TYPE_ADD = 0;
+ static final int ANIMATION_TYPE_REMOVE = 1;
+ static final int ANIMATION_TYPE_REMOVE_SWIPED_OUT = 2;
+ static final int ANIMATION_TYPE_TOP_PADDING_CHANGED = 3;
+ static final int ANIMATION_TYPE_START_DRAG = 4;
+ static final int ANIMATION_TYPE_SNAP_BACK = 5;
+ static final int ANIMATION_TYPE_ACTIVATED_CHILD = 6;
+ static final int ANIMATION_TYPE_DIMMED = 7;
+ static final int ANIMATION_TYPE_CHANGE_POSITION = 8;
final long eventStartTime;
final View changingView;
final int animationType;
final AnimationFilter filter;
final long length;
+ View viewAfterChangingView;
AnimationEvent(View view, int type) {
eventStartTime = AnimationUtils.currentAnimationTimeMillis();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index d572ea5..bd2541a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -208,6 +208,8 @@ public class StackScrollAlgorithm {
for (int i = 0; i < childCount; i++) {
ExpandableView v = (ExpandableView) hostView.getChildAt(i);
if (v.getVisibility() != View.GONE) {
+ StackScrollState.ViewState viewState = resultState.getViewStateForView(v);
+ viewState.notGoneIndex = state.visibleChildren.size();
state.visibleChildren.add(v);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 011411c..44e10be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -37,15 +37,14 @@ public class StackScrollState {
private static final String CHILD_NOT_FOUND_TAG = "StackScrollStateNoSuchChild";
private final ViewGroup mHostView;
+ private final int mRoundedRectCornerRadius;
private Map<ExpandableView, ViewState> mStateMap;
private final Rect mClipRect = new Rect();
- private int mBackgroundRoundedRectCornerRadius;
- private final Outline mChildOutline = new Outline();
public StackScrollState(ViewGroup hostView) {
mHostView = hostView;
mStateMap = new HashMap<ExpandableView, ViewState>();
- mBackgroundRoundedRectCornerRadius = hostView.getResources().getDimensionPixelSize(
+ mRoundedRectCornerRadius = mHostView.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_quantum_rounded_rect_radius);
}
@@ -66,6 +65,7 @@ public class StackScrollState {
viewState.height = child.getIntrinsicHeight();
viewState.gone = child.getVisibility() == View.GONE;
viewState.alpha = 1;
+ viewState.notGoneIndex = -1;
}
}
@@ -158,11 +158,15 @@ public class StackScrollState {
// apply clipping and shadow
float newNotificationEnd = newYTranslation + newHeight;
+ // In the unlocked shade we have to clip a little bit higher because of the rounded
+ // corners of the notifications.
+ float clippingCorrection = state.dimmed ? 0 : mRoundedRectCornerRadius;
+
// When the previous notification is swiped, we don't clip the content to the
// bottom of it.
float clipHeight = previousNotificationIsSwiped
? newHeight
- : newNotificationEnd - (previousNotificationEnd);
+ : newNotificationEnd - (previousNotificationEnd - clippingCorrection);
updateChildClippingAndBackground(child, newHeight,
clipHeight,
@@ -190,7 +194,7 @@ public class StackScrollState {
if (nextChild != null) {
ViewState nextState = getViewStateForView(nextChild);
boolean startIsAboveNext = nextState.yTranslation > speedBumpStart;
- speedBump.animateDivider(startIsAboveNext);
+ speedBump.animateDivider(startIsAboveNext, null /* onFinishedRunnable */);
// handle expanded case
if (speedBump.isExpanded()) {
@@ -272,6 +276,11 @@ public class StackScrollState {
boolean dimmed;
/**
+ * The index of the view, only accounting for views not equal to GONE
+ */
+ int notGoneIndex;
+
+ /**
* The location this view is currently rendered at.
*
* <p>See <code>LOCATION_</code> flags.</p>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index a9dcdd6..f019e6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -39,7 +39,11 @@ import java.util.Stack;
public class StackStateAnimator {
public static final int ANIMATION_DURATION_STANDARD = 360;
+ public static final int ANIMATION_DURATION_APPEAR_DISAPPEAR = 464;
public static final int ANIMATION_DURATION_DIMMED_ACTIVATED = 220;
+ public static final int ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING = 80;
+ public static final int ANIMATION_DELAY_PER_ELEMENT_MANUAL = 32;
+ private static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE = 2;
private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
@@ -62,10 +66,9 @@ public class StackStateAnimator {
private final Interpolator mFastOutSlowInInterpolator;
public NotificationStackScrollLayout mHostLayout;
- private ArrayList<NotificationStackScrollLayout.AnimationEvent> mHandledEvents =
- new ArrayList<>();
private ArrayList<NotificationStackScrollLayout.AnimationEvent> mNewEvents =
new ArrayList<>();
+ private ArrayList<View> mNewAddChildren = new ArrayList<>();
private Set<Animator> mAnimatorSet = new HashSet<Animator>();
private Stack<AnimatorListenerAdapter> mAnimationListenerPool
= new Stack<AnimatorListenerAdapter>();
@@ -96,57 +99,130 @@ public class StackStateAnimator {
mCurrentLength = NotificationStackScrollLayout.AnimationEvent.combineLength(mNewEvents);
for (int i = 0; i < childCount; i++) {
final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
+
StackScrollState.ViewState viewState = finalState.getViewStateForView(child);
- if (viewState == null) {
+ if (viewState == null || child.getVisibility() == View.GONE) {
continue;
}
- startAnimations(child, viewState);
-
child.setClipBounds(null);
+ startAnimations(child, viewState, finalState);
}
if (!isRunning()) {
// no child has preformed any animation, lets finish
onAnimationFinished();
}
+ mNewEvents.clear();
+ mNewAddChildren.clear();
}
/**
* Start an animation to the given viewState
*/
- private void startAnimations(final ExpandableView child, StackScrollState.ViewState viewState) {
+ private void startAnimations(final ExpandableView child, StackScrollState.ViewState viewState,
+ StackScrollState finalState) {
int childVisibility = child.getVisibility();
boolean wasVisible = childVisibility == View.VISIBLE;
final float alpha = viewState.alpha;
if (!wasVisible && alpha != 0 && !viewState.gone) {
child.setVisibility(View.VISIBLE);
}
+
+ boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation;
+ boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation;
+ boolean scaleChanging = child.getScaleX() != viewState.scale;
+ boolean alphaChanging = alpha != child.getAlpha();
+ boolean heightChanging = viewState.height != child.getActualHeight();
+ boolean wasAdded = mNewAddChildren.contains(child);
+ boolean hasDelays = mAnimationFilter.hasDelays;
+ boolean isDelayRelevant = yTranslationChanging || zTranslationChanging || scaleChanging ||
+ alphaChanging || heightChanging;
+ long delay = 0;
+ if (hasDelays && isDelayRelevant || wasAdded) {
+ delay = calculateChildAnimationDelay(viewState, finalState);
+ }
+
// start translationY animation
- if (child.getTranslationY() != viewState.yTranslation) {
- startYTranslationAnimation(child, viewState);
+ if (yTranslationChanging) {
+ startYTranslationAnimation(child, viewState, delay);
}
+
// start translationZ animation
- if (child.getTranslationZ() != viewState.zTranslation) {
- startZTranslationAnimation(child, viewState);
+ if (zTranslationChanging) {
+ startZTranslationAnimation(child, viewState, delay);
}
+
// start scale animation
- if (child.getScaleX() != viewState.scale) {
+ if (scaleChanging) {
startScaleAnimation(child, viewState);
}
+
// start alpha animation
- if (alpha != child.getAlpha()) {
- startAlphaAnimation(child, viewState);
+ if (alphaChanging) {
+ startAlphaAnimation(child, viewState, delay);
}
+
// start height animation
- if (viewState.height != child.getActualHeight()) {
- startHeightAnimation(child, viewState);
+ if (heightChanging) {
+ startHeightAnimation(child, viewState, delay);
}
+
// start dimmed animation
child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed);
+
+ if (wasAdded) {
+ child.performAddAnimation(delay);
+ }
+ }
+
+ private long calculateChildAnimationDelay(StackScrollState.ViewState viewState,
+ StackScrollState finalState) {
+ long minDelay = 0;
+ for (NotificationStackScrollLayout.AnimationEvent event : mNewEvents) {
+ long delayPerElement = ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING;
+ switch (event.animationType) {
+ case NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD: {
+ int ownIndex = viewState.notGoneIndex;
+ int changingIndex = finalState
+ .getViewStateForView(event.changingView).notGoneIndex;
+ int difference = Math.abs(ownIndex - changingIndex);
+ difference = Math.max(0, Math.min(DELAY_EFFECT_MAX_INDEX_DIFFERENCE,
+ difference - 1));
+ long delay = (DELAY_EFFECT_MAX_INDEX_DIFFERENCE - difference) * delayPerElement;
+ minDelay = Math.max(delay, minDelay);
+ break;
+ }
+ case NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT:
+ delayPerElement = ANIMATION_DELAY_PER_ELEMENT_MANUAL;
+ case NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE: {
+ int ownIndex = viewState.notGoneIndex;
+ boolean noNextView = event.viewAfterChangingView == null;
+ View viewAfterChangingView = noNextView
+ ? mHostLayout.getLastChildNotGone()
+ : event.viewAfterChangingView;
+
+ int nextIndex = finalState
+ .getViewStateForView(viewAfterChangingView).notGoneIndex;
+ if (ownIndex >= nextIndex) {
+ // we only have the view afterwards
+ ownIndex++;
+ }
+ int difference = Math.abs(ownIndex - nextIndex);
+ difference = Math.max(0, Math.min(DELAY_EFFECT_MAX_INDEX_DIFFERENCE,
+ difference - 1));
+ long delay = difference * delayPerElement;
+ minDelay = Math.max(delay, minDelay);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return minDelay;
}
private void startHeightAnimation(final ExpandableView child,
- StackScrollState.ViewState viewState) {
+ StackScrollState.ViewState viewState, long delay) {
Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT);
Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT);
int newEndValue = viewState.height;
@@ -185,6 +261,9 @@ public class StackStateAnimator {
animator.setInterpolator(mFastOutSlowInInterpolator);
long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
animator.setDuration(newDuration);
+ if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
+ animator.setStartDelay(delay);
+ }
animator.addListener(getGlobalAnimationFinishedListener());
// remove the tag when the animation is finished
animator.addListener(new AnimatorListenerAdapter() {
@@ -195,14 +274,14 @@ public class StackStateAnimator {
child.setTag(TAG_END_HEIGHT, null);
}
});
- startInstantly(animator);
+ startAnimator(animator);
child.setTag(TAG_ANIMATOR_HEIGHT, animator);
child.setTag(TAG_START_HEIGHT, child.getActualHeight());
child.setTag(TAG_END_HEIGHT, newEndValue);
}
private void startAlphaAnimation(final ExpandableView child,
- final StackScrollState.ViewState viewState) {
+ final StackScrollState.ViewState viewState, long delay) {
Float previousStartValue = getChildTag(child,TAG_START_ALPHA);
Float previousEndValue = getChildTag(child,TAG_END_ALPHA);
final float newEndValue = viewState.alpha;
@@ -236,14 +315,13 @@ public class StackStateAnimator {
child.getAlpha(), newEndValue);
animator.setInterpolator(mFastOutSlowInInterpolator);
// Handle layer type
- final int currentLayerType = child.getLayerType();
child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
animator.addListener(new AnimatorListenerAdapter() {
public boolean mWasCancelled;
@Override
public void onAnimationEnd(Animator animation) {
- child.setLayerType(currentLayerType, null);
+ child.setLayerType(View.LAYER_TYPE_NONE, null);
if (newEndValue == 0 && !mWasCancelled) {
child.setVisibility(View.INVISIBLE);
}
@@ -264,6 +342,9 @@ public class StackStateAnimator {
});
long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
animator.setDuration(newDuration);
+ if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
+ animator.setStartDelay(delay);
+ }
animator.addListener(getGlobalAnimationFinishedListener());
// remove the tag when the animation is finished
animator.addListener(new AnimatorListenerAdapter() {
@@ -272,14 +353,14 @@ public class StackStateAnimator {
}
});
- startInstantly(animator);
+ startAnimator(animator);
child.setTag(TAG_ANIMATOR_ALPHA, animator);
child.setTag(TAG_START_ALPHA, child.getAlpha());
child.setTag(TAG_END_ALPHA, newEndValue);
}
private void startZTranslationAnimation(final ExpandableView child,
- final StackScrollState.ViewState viewState) {
+ final StackScrollState.ViewState viewState, long delay) {
Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z);
Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z);
float newEndValue = viewState.zTranslation;
@@ -311,6 +392,9 @@ public class StackStateAnimator {
animator.setInterpolator(mFastOutSlowInInterpolator);
long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
animator.setDuration(newDuration);
+ if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
+ animator.setStartDelay(delay);
+ }
animator.addListener(getGlobalAnimationFinishedListener());
// remove the tag when the animation is finished
animator.addListener(new AnimatorListenerAdapter() {
@@ -321,14 +405,14 @@ public class StackStateAnimator {
child.setTag(TAG_END_TRANSLATION_Z, null);
}
});
- startInstantly(animator);
+ startAnimator(animator);
child.setTag(TAG_ANIMATOR_TRANSLATION_Z, animator);
child.setTag(TAG_START_TRANSLATION_Z, child.getTranslationZ());
child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
}
private void startYTranslationAnimation(final ExpandableView child,
- StackScrollState.ViewState viewState) {
+ StackScrollState.ViewState viewState, long delay) {
Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y);
Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y);
float newEndValue = viewState.yTranslation;
@@ -361,6 +445,9 @@ public class StackStateAnimator {
animator.setInterpolator(mFastOutSlowInInterpolator);
long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
animator.setDuration(newDuration);
+ if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
+ animator.setStartDelay(delay);
+ }
animator.addListener(getGlobalAnimationFinishedListener());
// remove the tag when the animation is finished
animator.addListener(new AnimatorListenerAdapter() {
@@ -371,7 +458,7 @@ public class StackStateAnimator {
child.setTag(TAG_END_TRANSLATION_Y, null);
}
});
- startInstantly(animator);
+ startAnimator(animator);
child.setTag(TAG_ANIMATOR_TRANSLATION_Y, animator);
child.setTag(TAG_START_TRANSLATION_Y, child.getTranslationY());
child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
@@ -425,18 +512,15 @@ public class StackStateAnimator {
child.setTag(TAG_END_SCALE, null);
}
});
- startInstantly(animator);
+ startAnimator(animator);
child.setTag(TAG_ANIMATOR_SCALE, animator);
child.setTag(TAG_START_SCALE, child.getScaleX());
child.setTag(TAG_END_SCALE, newEndValue);
}
- /**
- * Start an animator instantly instead of waiting on the next synchronization frame
- */
- public static void startInstantly(ValueAnimator animator) {
+ private void startAnimator(ValueAnimator animator) {
+ mAnimatorSet.add(animator);
animator.start();
- animator.setCurrentPlayTime(0);
}
/**
@@ -468,7 +552,6 @@ public class StackStateAnimator {
@Override
public void onAnimationStart(Animator animation) {
- mAnimatorSet.add(animation);
mWasCancelled = false;
}
};
@@ -497,8 +580,6 @@ public class StackStateAnimator {
}
private void onAnimationFinished() {
- mHandledEvents.clear();
- mNewEvents.clear();
mHostLayout.onChildAnimationFinished();
}
@@ -511,27 +592,60 @@ public class StackStateAnimator {
private void processAnimationEvents(
ArrayList<NotificationStackScrollLayout.AnimationEvent> animationEvents,
StackScrollState finalState) {
- mNewEvents.clear();
for (NotificationStackScrollLayout.AnimationEvent event : animationEvents) {
- View changingView = event.changingView;
- if (!mHandledEvents.contains(event)) {
- if (event.animationType == NotificationStackScrollLayout.AnimationEvent
- .ANIMATION_TYPE_ADD) {
-
- // This item is added, initialize it's properties.
- StackScrollState.ViewState viewState = finalState
- .getViewStateForView(changingView);
- if (viewState == null) {
- // The position for this child was never generated, let's continue.
- continue;
- }
- changingView.setAlpha(0);
- changingView.setTranslationY(viewState.yTranslation);
- changingView.setTranslationZ(viewState.zTranslation);
+ final ExpandableView changingView = (ExpandableView) event.changingView;
+ if (event.animationType ==
+ NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD) {
+
+ // This item is added, initialize it's properties.
+ StackScrollState.ViewState viewState = finalState
+ .getViewStateForView(changingView);
+ if (viewState == null) {
+ // The position for this child was never generated, let's continue.
+ continue;
+ }
+ if (changingView.getVisibility() == View.GONE) {
+ // The view was set to gone but the state never removed
+ finalState.removeViewStateForView(changingView);
+ continue;
}
- mHandledEvents.add(event);
- mNewEvents.add(event);
+ changingView.setAlpha(viewState.alpha);
+ changingView.setTranslationY(viewState.yTranslation);
+ changingView.setTranslationZ(viewState.zTranslation);
+ changingView.setActualHeight(viewState.height, false);
+ mNewAddChildren.add(changingView);
+
+ } else if (event.animationType ==
+ NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE) {
+ if (changingView.getVisibility() == View.GONE) {
+ continue;
+ }
+
+ // Find the amount to translate up. This is needed in order to understand the
+ // direction of the remove animation (either downwards or upwards)
+ StackScrollState.ViewState viewState = finalState
+ .getViewStateForView(event.viewAfterChangingView);
+ int actualHeight = changingView.getActualHeight();
+ // upwards by default
+ float translationDirection = -1.0f;
+ if (viewState != null) {
+ // there was a view after this one, Approximate the distance the next child
+ // travelled
+ translationDirection = ((viewState.yTranslation
+ - (changingView.getTranslationY() + actualHeight / 2.0f)) * 2 /
+ actualHeight);
+ translationDirection = Math.max(Math.min(translationDirection, 1.0f),-1.0f);
+
+ }
+ changingView.performRemoveAnimation(translationDirection, new Runnable() {
+ @Override
+ public void run() {
+ // remove the temporary overlay
+ mHostLayout.getOverlay().remove(changingView);
+ }
+ });
}
+ mNewEvents.add(event);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 9006c9a..25147b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -46,15 +46,23 @@ public class TvStatusBar extends BaseStatusBar {
}
@Override
- public void addNotification(IBinder key, StatusBarNotification notification) {
+ public void addNotification(StatusBarNotification notification) {
}
@Override
- public void updateNotification(IBinder key, StatusBarNotification notification) {
+ public void addNotificationInternal(StatusBarNotification notification) {
}
@Override
- public void removeNotification(IBinder key) {
+ public void updateNotification(StatusBarNotification notification) {
+ }
+
+ @Override
+ protected void removeNotificationInternal(String key) {
+ }
+
+ @Override
+ public void removeNotification(String key) {
}
@Override
@@ -113,7 +121,7 @@ public class TvStatusBar extends BaseStatusBar {
}
@Override
- protected void tick(IBinder key, StatusBarNotification n, boolean firstTime) {
+ protected void tick(StatusBarNotification n, boolean firstTime) {
}
@Override