diff options
Diffstat (limited to 'packages/SystemUI')
153 files changed, 4734 insertions, 1694 deletions
diff --git a/packages/SystemUI/res/anim/recents_from_app_enter.xml b/packages/SystemUI/res/anim/recents_from_app_enter.xml new file mode 100644 index 0000000..6abe8b3 --- /dev/null +++ b/packages/SystemUI/res/anim/recents_from_app_enter.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:shareInterpolator="false" + android:zAdjustment="top"> + <alpha android:fromAlpha="1.0" android:toAlpha="1.0" + android:fillEnabled="true" + android:fillBefore="true" android:fillAfter="true" + android:interpolator="@android:interpolator/fast_out_slow_in" + android:duration="0"/> +</set> diff --git a/packages/SystemUI/res/anim/recents_from_app_exit.xml b/packages/SystemUI/res/anim/recents_from_app_exit.xml new file mode 100644 index 0000000..1447a5a --- /dev/null +++ b/packages/SystemUI/res/anim/recents_from_app_exit.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:shareInterpolator="false" + android:zAdjustment="normal"> + + <!-- Animate the view out only after recents is visible --> + <alpha android:fromAlpha="1.0" android:toAlpha="0.0" + android:fillEnabled="true" + android:fillBefore="true" android:fillAfter="true" + android:interpolator="@android:interpolator/fast_out_slow_in" + android:duration="1"/> +</set> diff --git a/packages/SystemUI/res/anim/recents_from_launcher_enter.xml b/packages/SystemUI/res/anim/recents_from_launcher_enter.xml index 4bd7e82..305a82f 100644 --- a/packages/SystemUI/res/anim/recents_from_launcher_enter.xml +++ b/packages/SystemUI/res/anim/recents_from_launcher_enter.xml @@ -19,10 +19,10 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false" - android:zAdjustment="top"> - <alpha android:fromAlpha="0.0" android:toAlpha="1.0" + android:zAdjustment="normal"> + <alpha android:fromAlpha="1.0" android:toAlpha="1.0" android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@android:interpolator/accelerate_cubic" - android:duration="250"/> + android:interpolator="@android:interpolator/linear" + android:duration="200"/> </set> diff --git a/packages/SystemUI/res/anim/recents_from_launcher_exit.xml b/packages/SystemUI/res/anim/recents_from_launcher_exit.xml index becc9d0..863591f 100644 --- a/packages/SystemUI/res/anim/recents_from_launcher_exit.xml +++ b/packages/SystemUI/res/anim/recents_from_launcher_exit.xml @@ -19,10 +19,10 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false" - android:zAdjustment="normal"> + android:zAdjustment="top"> <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@android:interpolator/decelerate_cubic" - android:duration="250"/> + android:interpolator="@android:interpolator/linear_out_slow_in" + android:duration="200"/> </set> diff --git a/packages/SystemUI/res/anim/recents_from_unknown_enter.xml b/packages/SystemUI/res/anim/recents_from_unknown_enter.xml new file mode 100644 index 0000000..f68a143 --- /dev/null +++ b/packages/SystemUI/res/anim/recents_from_unknown_enter.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:shareInterpolator="false" + android:zAdjustment="top"> + <alpha android:fromAlpha="0.0" android:toAlpha="1.0" + android:fillEnabled="true" + android:fillBefore="true" android:fillAfter="true" + android:interpolator="@android:interpolator/fast_out_slow_in" + android:duration="200"/> +</set> diff --git a/packages/SystemUI/res/anim/recents_from_unknown_exit.xml b/packages/SystemUI/res/anim/recents_from_unknown_exit.xml new file mode 100644 index 0000000..31cf26a --- /dev/null +++ b/packages/SystemUI/res/anim/recents_from_unknown_exit.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:shareInterpolator="false" + android:zAdjustment="normal"> + <alpha android:fromAlpha="1.0" android:toAlpha="0.0" + android:fillEnabled="true" + android:fillBefore="true" android:fillAfter="true" + android:interpolator="@android:interpolator/fast_out_slow_in" + android:duration="200"/> +</set> diff --git a/packages/SystemUI/res/anim/recents_to_launcher_enter.xml b/packages/SystemUI/res/anim/recents_to_launcher_enter.xml new file mode 100644 index 0000000..adcefe0 --- /dev/null +++ b/packages/SystemUI/res/anim/recents_to_launcher_enter.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:shareInterpolator="false" + android:zAdjustment="normal"> + <alpha android:fromAlpha="0.0" android:toAlpha="1.0" + android:fillEnabled="true" + android:fillBefore="true" android:fillAfter="true" + android:interpolator="@android:interpolator/fast_out_linear_in" + android:duration="200"/> +</set> diff --git a/packages/SystemUI/res/anim/recents_to_launcher_exit.xml b/packages/SystemUI/res/anim/recents_to_launcher_exit.xml new file mode 100644 index 0000000..863591f --- /dev/null +++ b/packages/SystemUI/res/anim/recents_to_launcher_exit.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:shareInterpolator="false" + android:zAdjustment="top"> + <alpha android:fromAlpha="1.0" android:toAlpha="0.0" + android:fillEnabled="true" + android:fillBefore="true" android:fillAfter="true" + android:interpolator="@android:interpolator/linear_out_slow_in" + android:duration="200"/> +</set> diff --git a/packages/SystemUI/res/drawable-hdpi/recents_lower_gradient.9.png b/packages/SystemUI/res/drawable-hdpi/recents_lower_gradient.9.png Binary files differindex d4fdbf3..17100f7 100644 --- a/packages/SystemUI/res/drawable-hdpi/recents_lower_gradient.9.png +++ b/packages/SystemUI/res/drawable-hdpi/recents_lower_gradient.9.png diff --git a/packages/SystemUI/res/drawable-hdpi/recents_status_gradient.9.png b/packages/SystemUI/res/drawable-hdpi/recents_status_gradient.9.png Binary files differnew file mode 100644 index 0000000..e969d4c --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/recents_status_gradient.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/recents_lower_gradient.9.png b/packages/SystemUI/res/drawable-mdpi/recents_lower_gradient.9.png Binary files differindex 9fc1a3b..b53bd8f 100644 --- a/packages/SystemUI/res/drawable-mdpi/recents_lower_gradient.9.png +++ b/packages/SystemUI/res/drawable-mdpi/recents_lower_gradient.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/recents_status_gradient.9.png b/packages/SystemUI/res/drawable-mdpi/recents_status_gradient.9.png Binary files differnew file mode 100644 index 0000000..657f710 --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/recents_status_gradient.9.png diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_lower_gradient.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_lower_gradient.9.png Binary files differindex f38de93..09606f6 100644 --- a/packages/SystemUI/res/drawable-xhdpi/recents_lower_gradient.9.png +++ b/packages/SystemUI/res/drawable-xhdpi/recents_lower_gradient.9.png diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_status_gradient.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_status_gradient.9.png Binary files differnew file mode 100644 index 0000000..a444c55 --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/recents_status_gradient.9.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_lower_gradient.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_lower_gradient.9.png Binary files differindex 8194605..427cad9 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/recents_lower_gradient.9.png +++ b/packages/SystemUI/res/drawable-xxhdpi/recents_lower_gradient.9.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_status_gradient.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_status_gradient.9.png Binary files differnew file mode 100644 index 0000000..29cf44b --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/recents_status_gradient.9.png diff --git a/packages/SystemUI/res/drawable/ic_account_circle.xml b/packages/SystemUI/res/drawable/ic_account_circle.xml index a7e8514..4a4c1c1 100644 --- a/packages/SystemUI/res/drawable/ic_account_circle.xml +++ b/packages/SystemUI/res/drawable/ic_account_circle.xml @@ -22,7 +22,13 @@ Copyright (C) 2014 The Android Open Source Project android:viewportWidth="24.0" android:viewportHeight="24.0"/> + <group + android:scaleX="1.2" + android:scaleY="1.2" + android:pivotX="12.0" + android:pivotY="12.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"/> + </group> </vector> diff --git a/packages/SystemUI/res/drawable/ic_notify_zen.xml b/packages/SystemUI/res/drawable/ic_notify_zen.xml deleted file mode 100644 index c46455b..0000000 --- a/packages/SystemUI/res/drawable/ic_notify_zen.xml +++ /dev/null @@ -1,28 +0,0 @@ -<!-- -Copyright (C) 2014 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size - android:width="24dp" - android:height="24dp"/> - - <viewport - android:viewportWidth="48.0" - android:viewportHeight="48.0"/> - - <path - android:fill="#FFFFFFFF" - android:pathData="M4.0,24.0c0.0,11.0 9.0,20.0 20.0,20.0s20.0,-9.0 20.0,-20.0S35.0,4.0 24.0,4.0S4.0,13.0 4.0,24.0zM36.6,33.8L14.2,11.4C16.9,9.3 20.3,8.0 24.0,8.0c8.8,0.0 16.0,7.2 16.0,16.0C40.0,27.7 38.7,31.1 36.6,33.8zM8.0,24.0c0.0,-3.7 1.3,-7.1 3.4,-9.8L33.8,36.6C31.1,38.7 27.7,40.0 24.0,40.0C15.2,40.0 8.0,32.8 8.0,24.0z"/> -</vector> diff --git a/packages/SystemUI/res/drawable/notification_scrim.xml b/packages/SystemUI/res/drawable/notification_scrim.xml new file mode 100644 index 0000000..ff7e31f --- /dev/null +++ b/packages/SystemUI/res/drawable/notification_scrim.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + ~ Copyright (C) 2014 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="#34000000" /> + <corners android:radius="@*android:dimen/notification_material_rounded_rect_radius" /> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/recents_nav_bar_scrim.xml b/packages/SystemUI/res/drawable/recents_button_bg.xml index 4245d49..a4cb088 100644 --- a/packages/SystemUI/res/layout/recents_nav_bar_scrim.xml +++ b/packages/SystemUI/res/drawable/recents_button_bg.xml @@ -14,10 +14,5 @@ limitations under the License. --> -<ImageView - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal|bottom" - android:scaleType="fitXY" - android:src="@drawable/recents_lower_gradient" />
\ No newline at end of file +<ripple xmlns:android="http://schemas.android.com/apk/res/android" + android:color="?android:attr/colorControlHighlight" />
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher.xml b/packages/SystemUI/res/layout/keyguard_user_switcher.xml new file mode 100644 index 0000000..5648065 --- /dev/null +++ b/packages/SystemUI/res/layout/keyguard_user_switcher.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2014 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/keyguard_user_switcher" + android:orientation="vertical" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:gravity="end" + android:visibility="gone" + android:paddingTop="4dp"> +</LinearLayout> diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml new file mode 100644 index 0000000..691a80e --- /dev/null +++ b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + ~ Copyright (C) 2014 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:sysui="http://schemas.android.com/apk/res-auto" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:padding="8dp" + android:layout_marginEnd="8dp" + android:gravity="center_vertical" + android:clickable="true" + android:background="@drawable/ripple_drawable"> + <TextView android:id="@+id/name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="16dp" + android:textAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher.UserName" + /> + <com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/picture" + android:layout_width="48dp" + android:layout_height="48dp" + android:contentDescription="@null" + sysui:frameWidth="@dimen/keyguard_user_switcher_border_thickness" + sysui:activeFrameColor="@color/current_user_border_color" /> +</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/recents.xml b/packages/SystemUI/res/layout/recents.xml new file mode 100644 index 0000000..47740ee --- /dev/null +++ b/packages/SystemUI/res/layout/recents.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <!-- Status Bar Scrim View --> + <ImageView + android:id="@+id/status_bar_scrim" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal|top" + android:scaleType="fitXY" + android:src="@drawable/recents_status_gradient" /> + + <!-- Recents View --> + <com.android.systemui.recents.views.RecentsView + android:id="@+id/recents_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:focusable="true" /> + + <!-- Empty View --> + <ViewStub android:id="@+id/empty_view_stub" + android:layout="@layout/recents_empty" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + <!-- Fullscreen Transition View --> + <ViewStub android:id="@+id/fullscreen_overlay_stub" + android:layout="@layout/recents_fullscreen_overlay" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + <!-- Nav Bar Scrim View --> + <ImageView + android:id="@+id/nav_bar_scrim" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal|bottom" + android:scaleType="fitXY" + android:src="@drawable/recents_lower_gradient" /> +</FrameLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/recents_empty.xml b/packages/SystemUI/res/layout/recents_empty.xml index ac6450b..21d1711 100644 --- a/packages/SystemUI/res/layout/recents_empty.xml +++ b/packages/SystemUI/res/layout/recents_empty.xml @@ -16,12 +16,13 @@ <TextView xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="center" android:gravity="center" android:textSize="20sp" android:textColor="#ffffffff" - android:textStyle="italic" android:text="@string/recents_empty_message" android:fontFamily="sans-serif-light" + android:background="#80000000" android:visibility="gone" />
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/recents_fullscreen_overlay.xml b/packages/SystemUI/res/layout/recents_fullscreen_overlay.xml new file mode 100644 index 0000000..1d021f9 --- /dev/null +++ b/packages/SystemUI/res/layout/recents_fullscreen_overlay.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<com.android.systemui.recents.views.FullscreenTransitionOverlayView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:visibility="gone"> + <ImageView + android:id="@+id/image" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:scaleType="fitXY" /> +</com.android.systemui.recents.views.FullscreenTransitionOverlayView>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml index 85d2f16..1bab67a 100644 --- a/packages/SystemUI/res/layout/recents_task_view.xml +++ b/packages/SystemUI/res/layout/recents_task_view.xml @@ -32,8 +32,10 @@ android:id="@+id/application_icon" android:layout_width="@dimen/recents_task_view_application_icon_size" android:layout_height="@dimen/recents_task_view_application_icon_size" - android:layout_marginStart="16dp" - android:layout_gravity="center_vertical|start" /> + android:layout_marginStart="8dp" + android:layout_gravity="center_vertical|start" + android:padding="8dp" + android:background="@drawable/recents_button_bg" /> <TextView android:id="@+id/activity_description" android:layout_width="match_parent" @@ -56,6 +58,8 @@ android:layout_marginEnd="4dp" android:layout_gravity="center_vertical|end" android:padding="18dp" + android:background="@drawable/recents_button_bg" + android:visibility="invisible" android:src="@drawable/recents_dismiss_light" /> </com.android.systemui.recents.views.TaskBarView> </com.android.systemui.recents.views.TaskView> diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index cde83bf..b54ba1a 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -24,6 +24,7 @@ android:id="@+id/notification_panel" android:layout_width="match_parent" android:layout_height="match_parent" + android:background="@android:color/transparent" > <include @@ -91,6 +92,14 @@ <include layout="@layout/status_bar_expanded_header" /> + <ViewStub + android:id="@+id/keyguard_user_switcher" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_marginTop="@dimen/status_bar_header_height_keyguard" + android:layout_gravity="end" + android:layout="@layout/keyguard_user_switcher" /> + <include layout="@layout/keyguard_bottom_area" android:visibility="gone" /> diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml index 4028ec3..2e4c0ef 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml @@ -35,12 +35,66 @@ android:background="@drawable/notification_header_bg" android:clickable="true" /> + + <View android:id="@+id/header_spacer" + android:layout_height="8dp" + android:layout_width="0dp" /> + + <TextView + android:id="@+id/header_emergency_calls_only" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_below="@id/header_spacer" + android:paddingTop="12dp" + android:paddingStart="16dp" + android:paddingEnd="16dp" + android:visibility="gone" + android:textAppearance="@style/TextAppearance.StatusBar.Expanded.EmergencyCallsOnly" + android:text="@*android:string/emergency_calls_only" /> + + <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="8dp" /> + + <ImageButton android:id="@+id/settings_button" + style="@android:style/Widget.Material.Button.Borderless" + android:layout_toStartOf="@id/multi_user_switch" + android:layout_width="48dp" + android:layout_height="@dimen/status_bar_header_height" + android:layout_marginStart="8dp" + android:src="@drawable/ic_settings_24dp" + android:contentDescription="@string/accessibility_desc_quick_settings"/> + + <FrameLayout android:id="@+id/system_icons_container" + android:layout_width="wrap_content" + android:layout_height="@dimen/status_bar_header_height" + android:layout_toStartOf="@id/multi_user_switch" + android:layout_alignWithParentIfMissing="true" + android:layout_marginStart="16dp" + android:paddingEnd="2dp" /> + + <TextView + android:id="@+id/header_charging_info" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toEndOf="@id/system_icons_container" + android:layout_below="@id/header_spacer" + android:paddingTop="12dp" + android:paddingEnd="16dp" + android:paddingStart="4dp" + style="@style/TextAppearance.StatusBar.Expanded.ChargingInfo"/> + <RelativeLayout android:id="@+id/datetime" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="start" - android:paddingTop="16dp" + android:layout_below="@id/header_emergency_calls_only" + android:paddingTop="8dp" android:paddingBottom="16dp" android:paddingStart="16dp" android:paddingEnd="16dp" @@ -64,32 +118,6 @@ android:layout_below="@id/clock" /> </RelativeLayout> - - <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="8dp" - /> - - <ImageButton android:id="@+id/settings_button" - style="@android:style/Widget.Material.Button.Borderless" - android:layout_toStartOf="@id/multi_user_switch" - android:layout_width="48dp" - android:layout_height="@dimen/status_bar_header_height" - android:layout_marginStart="8dp" - android:src="@drawable/ic_settings_24dp" - android:contentDescription="@string/accessibility_desc_quick_settings"/> - - <FrameLayout android:id="@+id/system_icons_container" - android:layout_width="wrap_content" - android:layout_height="@dimen/status_bar_header_height" - android:layout_toStartOf="@id/multi_user_switch" - android:layout_marginEnd="2dp" - /> - <com.android.keyguard.CarrierText android:id="@+id/keyguard_carrier_text" android:layout_width="match_parent" @@ -106,6 +134,8 @@ layout="@layout/quick_settings_brightness_dialog" android:id="@+id/brightness_container" android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentBottom="true" /> <TextView diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml index c442f79..f0f50e1 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml @@ -49,4 +49,10 @@ android:layout_width="120dp" android:layout_height="wrap_content" /> + + <com.android.systemui.statusbar.NotificationScrimView + android:id="@+id/scrim_view" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + </com.android.systemui.statusbar.NotificationOverflowContainer> diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml index 5fabd3e..7663d54 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_row.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml @@ -48,4 +48,9 @@ android:padding="2dp" /> + <com.android.systemui.statusbar.NotificationScrimView + android:id="@+id/scrim_view" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + </com.android.systemui.statusbar.ExpandableNotificationRow> diff --git a/packages/SystemUI/res/layout/user_switcher_item.xml b/packages/SystemUI/res/layout/user_switcher_item.xml index 43a85e7..8df2f5a 100644 --- a/packages/SystemUI/res/layout/user_switcher_item.xml +++ b/packages/SystemUI/res/layout/user_switcher_item.xml @@ -21,10 +21,12 @@ android:layout_width="match_parent" android:layout_height="64dp" android:orientation="horizontal" + android:gravity="center_vertical" tools:context=".settings.UserSwitcherDialog"> <ImageView - android:layout_width="64dp" - android:layout_height="match_parent" + android:layout_width="48dp" + android:layout_height="48dp" + android:layout_marginStart="4dp" android:id="@+id/user_picture" tools:src="@drawable/dessert_zombiegingerbread"/> <TextView @@ -37,4 +39,11 @@ android:gravity="center_vertical" tools:text="Hiroshi Lockheimer" /> + <ImageView + android:layout_width="48dp" + android:layout_height="48dp" + android:layout_marginEnd="4dp" + android:src="@*android:drawable/ic_menu_delete" + android:id="@+id/user_delete" + android:background="?android:attr/selectableItemBackground"/> </LinearLayout> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 3bf38cb..d9c4c0c 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Geen onlangse programme nie"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Programinligting"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"soek"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Gelaai"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Laai tans"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> tot vol"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Laai nie"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netwerk word\ndalk gemonitor"</string> <string name="description_target_search" msgid="3091587249776033139">"Soek"</string> <string name="description_direction_up" msgid="7169032478259485180">"Gly op vir <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Sleep links vir kamera"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Totdat jy dit afskakel"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laai tans (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Gas"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ gas"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Een minuut lank"</item> <item quantity="other" msgid="6924190729213550991">"%d minute lank"</item> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index dea589d..f84f028 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"ምንም የቅርብ ጊዜ መተግበሪያዎች የሉም"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"የመተግበሪያ መረጃ"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"ፈልግ"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ባትሪ ሞልቷል"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"ኃይል በመሙላት ላይ"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> እስኪሞላ ድረስ"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"ባትሪ እየሞላ አይደለም"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"አውታረ መረብ\nክትትል ሊደረግበት ይችላል"</string> <string name="description_target_search" msgid="3091587249776033139">"ፍለጋ"</string> <string name="description_direction_up" msgid="7169032478259485180">"ለ<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ወደ ላይ አንሸራትት።"</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"ለካሜራ ወደግራ ያንሸራትቱ"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"ይህን እስኪያጠፉት ድረስ"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ሃይል በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"እንግዳ"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ እንግዳ"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"ለአንድ ደቂቃ"</item> <item quantity="other" msgid="6924190729213550991">"ለ%d ደቂቃዎች"</item> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index f369d12..44e6ffe 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"ليست هناك تطبيقات حديثة"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"معلومات التطبيق"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"بحث"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"تم الشحن"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"جارٍ الشحن"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> حتى الاكتمال"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"لا يتم الشحن"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"قد تكون الشبكة\nخاضعة للرقابة"</string> <string name="description_target_search" msgid="3091587249776033139">"بحث"</string> <string name="description_direction_up" msgid="7169032478259485180">"تمرير لأعلى لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"مرر سريعًا إلى اليمين لفتح الكاميرا"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"لحين تعطيل هذا الإعداد"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"جارٍ الشحن (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الامتلاء)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"المدعو"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ مدعو"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"لمدة دقيقة واحدة"</item> <item quantity="other" msgid="6924190729213550991">"لمدة %d من الدقائق"</item> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 2c3837a..71fb8b8 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Няма скорошни приложения"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информация за приложението"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"търсене"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Заредена"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Зарежда се"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> до пълно зареждане"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Не се зарежда"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежата може\nда се наблюдава"</string> <string name="description_target_search" msgid="3091587249776033139">"Търсене"</string> <string name="description_direction_up" msgid="7169032478259485180">"Плъзнете нагоре за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Прекарайте пръст наляво, за да включите камерата"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Докато не изключите това"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарежда се (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Гост"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ гост"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"За една минута"</item> <item quantity="other" msgid="6924190729213550991">"За %d минути"</item> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index c0b62d5..becd731 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -223,6 +223,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"No hi ha aplicacions recents."</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informació de l\'aplicació"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"S\'està carregant"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> per completar la càrrega"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"No s\'està carregant"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"És possible que la xarxa\nestigui controlada"</string> <string name="description_target_search" msgid="3091587249776033139">"Cerca"</string> <string name="description_direction_up" msgid="7169032478259485180">"Fes lliscar el dit cap amunt per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -241,6 +245,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Fes lliscar el dit cap a l\'esquerra per obrir la càmera."</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Fins que no ho desactivis"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregant (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar la càrrega)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Convidat"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Convidat"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Durant un minut"</item> <item quantity="other" msgid="6924190729213550991">"Durant %d minuts"</item> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index f7e3b14..97efe46 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -223,6 +223,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Žádné nedávné aplikace"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informace o aplikaci"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"vyhledat"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nabito"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Nabíjení"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do plného nabití"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nenabíjí se"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Síť může být\nmonitorována"</string> <string name="description_target_search" msgid="3091587249776033139">"Vyhledávání"</string> <string name="description_direction_up" msgid="7169032478259485180">"Přejeďte prstem nahoru: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string> @@ -241,6 +245,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Fotoaparát otevřete přejetím prstem vlevo."</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Dokud tuto funkci nevypnete"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Host"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"Přidat hosta"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Na jednu minutu"</item> <item quantity="other" msgid="6924190729213550991">"Na %d min"</item> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 05b72ce..a86157d 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Der er ingen seneste apps"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Oplysninger om applikationen"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"søg"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Opladet"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Oplader"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> indtil fuld opladet"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Oplader ikke"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netværket kan\nvære overvåget"</string> <string name="description_target_search" msgid="3091587249776033139">"Søgning"</string> <string name="description_direction_up" msgid="7169032478259485180">"Glid op for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Stryg til venstre for at åbne kameraet"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Indtil du slår denne indstilling fra"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Opladning (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Gæst"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Gæst"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"I ét minut"</item> <item quantity="other" msgid="6924190729213550991">"I %d minutter"</item> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 6e6280c..40e623a 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -223,6 +223,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Keine neuen Apps"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"App-Info"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"Suche"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Aufgeladen"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Wird aufgeladen"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Voll in <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Wird nicht aufgeladen"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netzwerk wird\neventuell überwacht."</string> <string name="description_target_search" msgid="3091587249776033139">"Suche"</string> <string name="description_direction_up" msgid="7169032478259485180">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach oben schieben"</string> @@ -241,6 +245,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Zum Öffnen der Kamera nach links wischen"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Bis zur Deaktivierung"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Wird aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Gast"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Gast"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Für eine Minute"</item> <item quantity="other" msgid="6924190729213550991">"Für %d Minuten"</item> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index a99e91e..5e5aa6a 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -223,6 +223,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Καμία πρόσφατη εφαρμογή"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Πληροφορίες εφαρμογής"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"αναζήτηση"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Φορτίστηκε"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Φόρτιση"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> για πλήρη φόρτιση"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Δεν φορτίζει"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Το δίκτυο μπορεί\nνα παρακολουθείται"</string> <string name="description_target_search" msgid="3091587249776033139">"Αναζήτηση"</string> <string name="description_direction_up" msgid="7169032478259485180">"Κύλιση προς τα επάνω για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -241,6 +245,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Σύρετε αριστερά για τη φωτογραφική μηχανή"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Μέχρι να το απενεργοποιήσετε"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Επισκέπτης"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Επισκέπτης"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Για ένα λεπτό"</item> <item quantity="other" msgid="6924190729213550991">"Για %d λεπτά"</item> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 0938b28..82ee78c 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"No recent apps"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Charged"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Charging"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> until full"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Not charging"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string> <string name="description_target_search" msgid="3091587249776033139">"Search"</string> <string name="description_direction_up" msgid="7169032478259485180">"Slide up for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Swipe left for camera"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Until you turn this off"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Guest"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Guest"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"For one minute"</item> <item quantity="other" msgid="6924190729213550991">"For %d minutes"</item> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 0938b28..82ee78c 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"No recent apps"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Charged"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Charging"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> until full"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Not charging"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string> <string name="description_target_search" msgid="3091587249776033139">"Search"</string> <string name="description_direction_up" msgid="7169032478259485180">"Slide up for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Swipe left for camera"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Until you turn this off"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Guest"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Guest"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"For one minute"</item> <item quantity="other" msgid="6924190729213550991">"For %d minutes"</item> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index cfa809c..4145a29 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -223,6 +223,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"No hay aplicaciones recientes."</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Cargando"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> para completarse"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"No se está cargando"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Es posible que la red\nesté supervisada."</string> <string name="description_target_search" msgid="3091587249776033139">"Buscar"</string> <string name="description_direction_up" msgid="7169032478259485180">"Desliza el dedo hacia arriba para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -241,6 +245,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Desliza hacia la izquierda para acceder a la cámara."</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Hasta que lo desactives"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (faltan <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Invitado"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"Agregar invitado"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Durante un minuto"</item> <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 242a7d0..b1dc302 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"No hay aplicaciones recientes"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Cargando"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> para completarse"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"No se está cargando"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La red se\npuede supervisar"</string> <string name="description_target_search" msgid="3091587249776033139">"Buscar"</string> <string name="description_direction_up" msgid="7169032478259485180">"Desliza el dedo hacia arriba para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Desliza el dedo hacia la izquierda para acceder a la cámara"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Hasta apagar el dispositivo"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hasta completar)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Invitado"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"Añadir invitado"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Durante un minuto"</item> <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item> diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml index bc9a6e6..8aab7f3 100644 --- a/packages/SystemUI/res/values-et-rEE/strings.xml +++ b/packages/SystemUI/res/values-et-rEE/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Hiljutisi rakendusi pole"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Rakenduste teave"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"otsing"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Laetud"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Laadimine"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Täislaadimiseks kulub <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Ei laadi"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Võrku võidakse\njälgida"</string> <string name="description_target_search" msgid="3091587249776033139">"Otsing"</string> <string name="description_direction_up" msgid="7169032478259485180">"Lohistage üles: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -237,6 +241,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Kaamera kasutamiseks pühkige vasakule"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Kuni lülitate selle välja"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Külaline"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ külaline"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Üheks minutiks"</item> <item quantity="other" msgid="6924190729213550991">"%d minutiks"</item> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 8495828..3595b6a 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"هیچ برنامه جدیدی موجود نیست"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"اطلاعات برنامه"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"جستجو"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"شارژ کامل شد"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"در حال شارژ شدن"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> مانده تا شارژ کامل شود"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"شارژ نمیشود"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ممکن است شبکه\nتحت نظارت باشد"</string> <string name="description_target_search" msgid="3091587249776033139">"جستجو"</string> <string name="description_direction_up" msgid="7169032478259485180">"لغزاندن به بالا برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"برای دوربین انگشت را تند به سمت راست بکشید"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"تا وقتی آن را خاموش کنید"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"در حال شارژ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"مهمان"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ مهمان"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"برای یک دقیقه"</item> <item quantity="other" msgid="6924190729213550991">"برای %d دقیقه"</item> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index c73caf4..019fea0 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Ei viimeaikaisia sovelluksia"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Sovellustiedot"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"haku"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Ladattu"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Ladataan"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> kunnes täynnä"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Ei lataudu"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Verkkoa saatetaan\nvalvoa"</string> <string name="description_target_search" msgid="3091587249776033139">"Haku"</string> <string name="description_direction_up" msgid="7169032478259485180">"Liu\'uta ylös ja <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Avaa kamera pyyhkäisemällä oikealle"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Kunnes poistat tämän käytöstä"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ladataan (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kunnes täynnä)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Vieras"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Vieras"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Minuutiksi"</item> <item quantity="other" msgid="6924190729213550991">"%d minuutiksi"</item> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 179b54d..03ac011 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -223,6 +223,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Aucune application récente"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Détails de l\'application"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Chargée"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Charge en cours..."</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Chargée dans <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"N\'est pas en charge"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Le réseau peut\nêtre surveillé."</string> <string name="description_target_search" msgid="3091587249776033139">"Recherche"</string> <string name="description_direction_up" msgid="7169032478259485180">"Faire glisser le doigt vers le haut : <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string> @@ -241,6 +245,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Balayez l\'écran vers la gauche pour accéder à l\'appareil photo"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Jusqu\'à la désactivation"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours... (chargée à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Invité"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"Ajouter un invité"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Pendant une minute"</item> <item quantity="other" msgid="6924190729213550991">"Pendant %d minutes"</item> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 3334125..d11c9be 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -223,6 +223,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Aucune application récente"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informations sur l\'application"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Chargé"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"En charge"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Chargé dans <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"N\'est pas en charge"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Le réseau peut\nêtre surveillé."</string> <string name="description_target_search" msgid="3091587249776033139">"Rechercher"</string> <string name="description_direction_up" msgid="7169032478259485180">"Faites glisser vers le haut pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -241,6 +245,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Balayer l\'écran vers la gauche pour accéder à l\'appareil photo"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Jusqu\'à la désactivation"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours… (chargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Invité"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"Ajouter un invité"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Pendant une minute"</item> <item quantity="other" msgid="6924190729213550991">"Pendant %d minutes"</item> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index fe28ec5..c33c1d5 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"कोई हाल ही का ऐप्स नहीं"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"एप्लिकेशन जानकारी"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"खोज"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"चार्ज हो गई है"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"चार्ज हो रही है"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"पूर्ण होने में <xliff:g id="CHARGING_TIME">%s</xliff:g> शेष"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"चार्ज नहीं हो रही है"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"नेटवर्क को\nमॉनीटर किया जा सकता है"</string> <string name="description_target_search" msgid="3091587249776033139">"खोजें"</string> <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए ऊपर स्लाइड करें."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"कैमरे के लिए बाएं स्वाइप करें"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"जब तक आप इसे बंद नहीं कर देते"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हो रहा है (पूर्ण होने में <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> शेष)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"अतिथि"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ अतिथि"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"एक मिनट के लिए"</item> <item quantity="other" msgid="6924190729213550991">"%d मिनट के लिए"</item> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 4ee3e32..024be82 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Nema nedavnih aplikacija"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjeno"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Punjenje"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do napunjenosti"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Ne puni se"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mreža se\nmožda prati"</string> <string name="description_target_search" msgid="3091587249776033139">"Pretraživanje"</string> <string name="description_direction_up" msgid="7169032478259485180">"Kliznite prema gore za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Prijeđite prstom ulijevo za fotoaparat"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Dok ne isključite"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Gost"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ gost"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Jednu minutu"</item> <item quantity="other" msgid="6924190729213550991">"%d min"</item> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 95af816..deeb7f4 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Nincsenek nemrég használt alkalmazások"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Az alkalmazás adatai"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"keresés"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Feltöltve"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Töltés"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> a teljes töltöttségig"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nem töltődik"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Lehet, hogy a\nhálózat felügyelt"</string> <string name="description_target_search" msgid="3091587249776033139">"Keresés"</string> <string name="description_direction_up" msgid="7169032478259485180">"A(z) <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> művelethez csúsztassa felfelé."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"A fényképezőgép eléréséhez csúsztassa ujját balra"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Amíg ki nem kapcsolja ezt"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Vendég"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ vendég"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Egy percen át"</item> <item quantity="other" msgid="6924190729213550991">"%d percen át"</item> diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml index 637d85f..4424338 100644 --- a/packages/SystemUI/res/values-hy-rAM/strings.xml +++ b/packages/SystemUI/res/values-hy-rAM/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Նոր հավելվածներ չկան"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Հավելվածի մասին"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"որոնել"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Լիցքավորված է"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Լիցքավորվում է"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Լրիվ լիցքավորմանը մնաց <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Չի լիցքավորվում"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Ցանցը կարող է\nվերահսկվել"</string> <string name="description_target_search" msgid="3091587249776033139">"Որոնել"</string> <string name="description_direction_up" msgid="7169032478259485180">"Սահեցրեք վերև <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Խցիկի համար սահեցրեք ձախ"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Քանի դեռ չեք անջատել"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> մինչև լրիվ լիցքավորումը)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Հյուր"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Հյուր"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Մեկ րոպե"</item> <item quantity="other" msgid="6924190729213550991">"%d րոպե"</item> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 3cd82a7..5dbd490 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Tidak ada aplikasi terkini"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Info Aplikasi"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"telusuri"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Terisi"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Mengisi daya"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> sampai penuh"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Tidak mengisi daya"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Jaringan bisa\ndiawasi"</string> <string name="description_target_search" msgid="3091587249776033139">"Telusuri"</string> <string name="description_direction_up" msgid="7169032478259485180">"Geser ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Gesek ke kiri untuk kamera"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Hingga Anda menonaktifkan ini"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengisi daya (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Tamu"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Tamu"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Selama satu menit"</item> <item quantity="other" msgid="6924190729213550991">"Selama %d menit"</item> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index b62d75a..ddb7669 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -223,6 +223,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Nessuna app recente"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informazioni sull\'applicazione"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carica"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"In carica"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> al termine della carica"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Non in carica"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La rete potrebbe\nessere monitorata"</string> <string name="description_target_search" msgid="3091587249776033139">"Ricerca"</string> <string name="description_direction_up" msgid="7169032478259485180">"Su per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -241,6 +245,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Scorri verso sinistra per accedere alla fotocamera"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Fino alla disattivazione"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"In carica (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Ospite"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ ospite"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Per un minuto"</item> <item quantity="other" msgid="6924190729213550991">"Per %d minuti"</item> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index e1e7e00..5b68451 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"אין אפליקציות אחרונות"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"מידע על האפליקציה"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"חפש"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"טעון"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"טוען"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> עד למילוי"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"לא בטעינה"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ייתכן שהרשת\nמנוטרת"</string> <string name="description_target_search" msgid="3091587249776033139">"חיפוש"</string> <string name="description_direction_up" msgid="7169032478259485180">"הסט למעלה כדי להציג <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"החלק שמאלה להפעלת המצלמה"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"עד שתכבה"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"טוען (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד לסיום)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"אורח"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ אורח"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"למשך דקה אחת"</item> <item quantity="other" msgid="6924190729213550991">"למשך %d דקות"</item> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index b6359e9..6ebd5c7 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -223,6 +223,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"最近使ったアプリはありません"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"アプリ情報"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"検索"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"充電が完了しました"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"充電しています"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"充電完了まで<xliff:g id="CHARGING_TIME">%s</xliff:g>"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"充電していません"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ネットワークが監視される\n場合があります"</string> <string name="description_target_search" msgid="3091587249776033139">"検索します"</string> <string name="description_direction_up" msgid="7169032478259485180">"上にスライドして<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>を行います。"</string> @@ -241,6 +245,8 @@ <string name="camera_hint" msgid="5241441720959174226">"左にスワイプしてカメラを表示"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"ユーザーがOFFにするまで"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中(フルになるまで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"ゲスト"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ ゲスト"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"1分"</item> <item quantity="other" msgid="6924190729213550991">"%d分"</item> diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml index 973cd63..a35c821 100644 --- a/packages/SystemUI/res/values-ka-rGE/strings.xml +++ b/packages/SystemUI/res/values-ka-rGE/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"ბოლო აპები არ არის"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"აპლიკაციის შესახებ"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"ძიება"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"დატენილია"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"მიმდინარეობს დატენვა"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> სრულად დატენვამდე"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"არ იტენება"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"შესაძლოა ქსელზე\nმონიტორინგი ხორციელდებოდეს"</string> <string name="description_target_search" msgid="3091587249776033139">"ძიება"</string> <string name="description_direction_up" msgid="7169032478259485180">"გაასრიალეთ ზემოთ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"კამერისთვის მარცხენა შენაცვლება"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"სანამ ამას გამორთავდეთ"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>-ის შეცვლა დასრულებამდე)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"სტუმარი"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ სტუმარი"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"ერთი წუთით"</item> <item quantity="other" msgid="6924190729213550991">"%d წუთით"</item> diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml index 4a4a2bddf..29c5e5c 100644 --- a/packages/SystemUI/res/values-km-rKH/strings.xml +++ b/packages/SystemUI/res/values-km-rKH/strings.xml @@ -70,7 +70,7 @@ <string name="screenshot_saving_ticker" msgid="7403652894056693515">"កំពុងរក្សាទុករូបថតអេក្រង់…"</string> <string name="screenshot_saving_title" msgid="8242282144535555697">"កំពុងរក្សាទុករូបថតអេក្រង់..."</string> <string name="screenshot_saving_text" msgid="2419718443411738818">"រូបថតអេក្រង់កំពុងត្រូវបានរក្សាទុក។"</string> - <string name="screenshot_saved_title" msgid="6461865960961414961">"បានចាប់យករូបថតអេក្រង់។"</string> + <string name="screenshot_saved_title" msgid="6461865960961414961">"បានចាប់យករូបថតអេក្រង់។"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"ប៉ះ ដើម្បីមើលរូបថតអេក្រង់របស់អ្នក។"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"មិនអាចចាប់យករូបថតអេក្រង់។"</string> <string name="screenshot_failed_text" msgid="8134011269572415402">"មិនអាចរក្សាទុករូបថតអេក្រង់។ ឧបករណ៍ផ្ទុកអាចកំពុងប្រើ។"</string> @@ -147,7 +147,7 @@ <string name="accessibility_remove_notification" msgid="3603099514902182350">"សម្អាតការជូនដំណឹង។"</string> <string name="accessibility_gps_enabled" msgid="3511469499240123019">"បានបើក GPS ។"</string> <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"ទទួល GPS ។"</string> - <string name="accessibility_tty_enabled" msgid="4613200365379426561">"បានបើកម៉ាស៊ីនអង្គុលីលេខ"</string> + <string name="accessibility_tty_enabled" msgid="4613200365379426561">"បានបើកម៉ាស៊ីនអង្គុលីលេខ"</string> <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"កម្មវិធីរោទ៍ញ័រ។"</string> <string name="accessibility_ringer_silent" msgid="9061243307939135383">"កម្មវិធីរោទ៍ស្ងាត់។"</string> <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> បដិសេធ។"</string> @@ -197,7 +197,7 @@ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"បញ្ឈរ"</string> <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"ទេសភាព"</string> <string name="quick_settings_ime_label" msgid="7073463064369468429">"វិធីសាស្ត្របញ្ចូល"</string> - <string name="quick_settings_location_label" msgid="5011327048748762257">"ទីតាំង"</string> + <string name="quick_settings_location_label" msgid="5011327048748762257">"ទីតាំង"</string> <string name="quick_settings_location_off_label" msgid="7464544086507331459">"ទីតាំងបានបិទ"</string> <string name="quick_settings_media_device_label" msgid="1302906836372603762">"ឧបករណ៍មេឌៀ"</string> <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string> @@ -221,7 +221,11 @@ <string name="recents_empty_message" msgid="7883614615463619450">"មិនមានកម្មវិធីថ្មីៗ"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"ព័ត៌មានកម្មវិធី"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"ស្វែងរក"</string> - <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"បណ្ដាញអាច\nត្រូវបានត្រួតពិនិត្យ"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"បានបញ្ចូលថ្ម"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"កំពុងបញ្ចូលថ្ម"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> រហូតដល់ពេញ"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"មិនកំពុងបញ្ចូលថ្ម"</string> + <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"បណ្ដាញអាច\nត្រូវបានត្រួតពិនិត្យ"</string> <string name="description_target_search" msgid="3091587249776033139">"ស្វែងរក"</string> <string name="description_direction_up" msgid="7169032478259485180">"រុញឡើងលើដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string> <string name="description_direction_left" msgid="7207478719805562165">"រុញទៅឆ្វេងដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"អូសទៅឆ្វេងដើម្បីប្រើម៉ាស៊ីនថត"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"រហូតដល់ពេលអ្នកបិទវា"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"កំពុងបញ្ចូលថ្ម (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើបពេញ)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"ភ្ញៀវ"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ ភ្ញៀវ"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"សម្រាប់មួយនាទី"</item> <item quantity="other" msgid="6924190729213550991">"សម្រាប់ %d នាទី"</item> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 5435a7b..0ffb4b8 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -223,6 +223,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"최근에 사용한 앱 없음"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"애플리케이션 정보"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"검색"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"충전됨"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"충전 중"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"완충까지 <xliff:g id="CHARGING_TIME">%s</xliff:g> 남음"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"충전 안함"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"네트워크가\n모니터링될 수 있음"</string> <string name="description_target_search" msgid="3091587249776033139">"검색"</string> <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>하려면 위로 슬라이드"</string> @@ -241,6 +245,8 @@ <string name="camera_hint" msgid="5241441720959174226">"카메라를 사용하려면 왼쪽으로 스와이프하세요."</string> <string name="zen_mode_forever" msgid="7420011936770086993">"이 기능을 사용 중지할 때까지"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"손님"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"새 손님 추가"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"1분 동안"</item> <item quantity="other" msgid="6924190729213550991">"%d분 동안"</item> diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml index 604714b..b765fb7 100644 --- a/packages/SystemUI/res/values-lo-rLA/strings.xml +++ b/packages/SystemUI/res/values-lo-rLA/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"ບໍ່ມີແອັບຯທີ່ຫາກໍໃຊ້"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"ຂໍ້ມູນແອັບພລິເຄຊັນ"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"ຊອກຫາ"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ສາກເຕັມແລ້ວ."</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"ກຳລັງສາກໄຟ"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> ຈຶ່ງຈະເຕັມ"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"ບໍ່ໄດ້ສາກໄຟ"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ເຄືອຄ່າຍອາດ\nຖືກຕິດຕາມ"</string> <string name="description_target_search" msgid="3091587249776033139">"ຊອກຫາ"</string> <string name="description_direction_up" msgid="7169032478259485180">"ເລື່ອນຂຶ້ນເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -237,8 +241,10 @@ <string name="keyguard_unlock" msgid="8043466894212841998">"ເລື່ອນຂຶ້ນເພື່ອປົດລັອກ"</string> <string name="phone_hint" msgid="3101468054914424646">"ປັດຂວາເພື່ອໃຊ້ໂທລະສັບ"</string> <string name="camera_hint" msgid="5241441720959174226">"ປັດຊ້າຍເພື່ອໃຊ້ກ້ອງ"</string> - <string name="zen_mode_forever" msgid="7420011936770086993">"ຈົນກວ່າທ່ານຈະປິດ"</string> + <string name="zen_mode_forever" msgid="7420011936770086993">"ຈົນກວ່າທ່ານຈະປິດ"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ກຳລັງສາກໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າຈະເຕັມ)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"ແຂກ"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ ແຂກ"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"ເປັນເວລານຶ່ງນາທີ"</item> <item quantity="other" msgid="6924190729213550991">"ເປັນເວລາ %d ນາທີ"</item> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 6563d45..cc1ac06 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Nėra naujausių programų"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Programos informacija"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"paieška"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Įkrautas"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Kraunamas"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> iki visiško įkrovimo"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Neįkraunamas"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tinklas gali\nbūti stebimas"</string> <string name="description_target_search" msgid="3091587249776033139">"Paieška"</string> <string name="description_direction_up" msgid="7169032478259485180">"Slyskite aukštyn link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Perbraukite į kairę, kad būtų įjungtas fotoaparatas"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Kol išjungsite"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Svečias"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Svečias"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"1 min."</item> <item quantity="other" msgid="6924190729213550991">"%d min."</item> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 4c4031e..4e3a676 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Nav nesen izmantotu lietotņu"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informācija par lietojumprogrammu"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"Meklēt"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Akumulators uzlādēts"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Notiek uzlāde"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> līdz pilnam akumulatoram"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nenotiek uzlāde"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tīkls var\ntikt uzraudzīts"</string> <string name="description_target_search" msgid="3091587249776033139">"Meklēt"</string> <string name="description_direction_up" msgid="7169032478259485180">"Velciet uz augšu, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Lai lietotu kameru, velciet pa kreisi."</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Līdz brīdim, kad izslēgsiet"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Notiek uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Viesis"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+Viesis"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Vienu minūti"</item> <item quantity="other" msgid="6924190729213550991">"%d min"</item> diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml index 2bb37f6..a2568d1 100644 --- a/packages/SystemUI/res/values-mn-rMN/strings.xml +++ b/packages/SystemUI/res/values-mn-rMN/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Сүүлд ашигласан апп байхгүй"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Аппликешны мэдээлэл"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"хайх"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Цэнэглэгдсэн"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Цэнэглэж байна"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"дүүргэхэд <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Цэнэглэхгүй байна"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Сүлжээ хянагдаж\nбайж болзошгүй"</string> <string name="description_target_search" msgid="3091587249776033139">"Хайх"</string> <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-г гулсуулах."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Камер гаргахын тулд зүүн шударна уу"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Таныг унтраах хүртэл"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Зочин"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Зочин"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Нэг минутын турш"</item> <item quantity="other" msgid="6924190729213550991">"%d минутын турш"</item> diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml index 7f46211..2fed4bd 100644 --- a/packages/SystemUI/res/values-ms-rMY/strings.xml +++ b/packages/SystemUI/res/values-ms-rMY/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Tiada apl terbaharu"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Maklumat Aplikasi"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"cari"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Sudah dicas"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Mengecas"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Lagi <xliff:g id="CHARGING_TIME">%s</xliff:g> untuk penuh"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Tidak mengecas"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rangkaian mungkin\nboleh dipantau"</string> <string name="description_target_search" msgid="3091587249776033139">"Carian"</string> <string name="description_direction_up" msgid="7169032478259485180">"Luncurkan ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Leret ke kiri untuk kamera"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Sehingga anda matikan"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengecas (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Tetamu"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Tetamu"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Selama satu minit"</item> <item quantity="other" msgid="6924190729213550991">"Selama %d minit"</item> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 91b14da..cecbe7a 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Ingen nylige apper"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformasjon"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"Søk"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Oppladet"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Lader"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Fulladet om <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Lader ikke"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nettverket kan\nvære overvåket"</string> <string name="description_target_search" msgid="3091587249776033139">"Søk"</string> <string name="description_direction_up" msgid="7169032478259485180">"Dra opp for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Sveip mot venstre for å åpne kameraet"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Inntil du slår av funksjonen"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Lader (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Gjest"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Gjest"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"I ett minutt"</item> <item quantity="other" msgid="6924190729213550991">"I %d minutter"</item> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index fd7337e..b6ffecf 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Geen recente apps"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"App-informatie"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"zoeken"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Opgeladen"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Opladen"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> tot volledig opgeladen"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Wordt niet opgeladen"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netwerk kan\nworden gecontroleerd"</string> <string name="description_target_search" msgid="3091587249776033139">"Zoeken"</string> <string name="description_direction_up" msgid="7169032478259485180">"Veeg omhoog voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Veeg naar links voor camera"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Totdat u dit uitschakelt"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Gast"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Gast"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Eén minuut"</item> <item quantity="other" msgid="6924190729213550991">"%d minuten"</item> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 4d582e2..05dcd82 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Brak ostatnio uruchomionych aplikacji"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacje o aplikacji"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"szukaj"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Naładowana"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Ładuje się"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do pełnego naładowania"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nie ładuje"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Sieć może być\nmonitorowana"</string> <string name="description_target_search" msgid="3091587249776033139">"Szukaj"</string> <string name="description_direction_up" msgid="7169032478259485180">"Przesuń w górę: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Przesuń w lewo, by przełączyć się na aparat"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Dopóki nie wyłączysz"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ładuje się (pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Gość"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"Dodaj gościa"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Przez minutę"</item> <item quantity="other" msgid="6924190729213550991">"Przez %d min"</item> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index d576ebb..657e03f 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Nenhuma aplicação recente"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações da aplicação"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"A carregar"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> até ficar completa"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Não está a carregar"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"A rede pode ser\nmonitorizada"</string> <string name="description_target_search" msgid="3091587249776033139">"Pesquisar"</string> <string name="description_direction_up" msgid="7169032478259485180">"Deslize para cima para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Deslize rapidamente para a esquerda para aceder à câmara"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Até que o utilizador desative"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"A carregar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Convidado"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Convidado"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Durante um minuto"</item> <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index caffae9..bcf7431 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -223,6 +223,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Nenhum app recente"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações do aplicativo"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Carregando"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> até concluir"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Não está carregando"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"A rede pode estar\nsob monitoração"</string> <string name="description_target_search" msgid="3091587249776033139">"Pesquisar"</string> <string name="description_direction_up" msgid="7169032478259485180">"Para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>, deslize para cima."</string> @@ -241,6 +245,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Deslize para a esquerda para usar a câmera"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Até você desativar"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até concluir)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Convidado"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ convidado"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Por 1 minuto"</item> <item quantity="other" msgid="6924190729213550991">"Por %d minutos"</item> diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml index 0a5a698..689aaff 100644 --- a/packages/SystemUI/res/values-rm/strings.xml +++ b/packages/SystemUI/res/values-rm/strings.xml @@ -413,6 +413,14 @@ <skip /> <!-- no translation found for recents_search_bar_label (8074997400187836677) --> <skip /> + <!-- no translation found for expanded_header_battery_charged (5945855970267657951) --> + <skip /> + <!-- no translation found for expanded_header_battery_charging (205623198487189724) --> + <skip /> + <!-- no translation found for expanded_header_battery_charging_with_time (457559884275395376) --> + <skip /> + <!-- no translation found for expanded_header_battery_not_charging (4798147152367049732) --> + <skip /> <!-- no translation found for ssl_ca_cert_warning (9005954106902053641) --> <skip /> <!-- no translation found for description_target_search (3091587249776033139) --> @@ -443,6 +451,10 @@ <skip /> <!-- no translation found for keyguard_indication_charging_time (1757251776872835768) --> <skip /> + <!-- no translation found for guest_nickname (8059989128963789678) --> + <skip /> + <!-- no translation found for guest_new_guest (4259024453643879653) --> + <skip /> <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) --> <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) --> <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) --> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 8d5fddc..8ec3621 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Nicio aplicație recentă"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informații despre aplicație"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"căutare"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"S-a încărcat"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Se încarcă"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> până la încărcare completă"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nu se încarcă"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rețeaua poate\nfi monitorizată"</string> <string name="description_target_search" msgid="3091587249776033139">"Căutaţi"</string> <string name="description_direction_up" msgid="7169032478259485180">"Glisaţi în sus pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Glisați la stânga pentru a accesa camera foto"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Până la dezactivare"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Se încarcă (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Invitat"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Invitat"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Timp de un minut"</item> <item quantity="other" msgid="6924190729213550991">"Timp de %d (de) minute"</item> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index e940893..8c59e05 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -223,6 +223,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Ничего не найдено."</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Сведения о приложении"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"поиск"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Батарея заряжена"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Зарядка батареи"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> до полной зарядки"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Не заряжается"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Действия в сети\nмогут отслеживаться"</string> <string name="description_target_search" msgid="3091587249776033139">"Поиск"</string> <string name="description_direction_up" msgid="7169032478259485180">"Проведите вверх, чтобы <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -241,6 +245,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Чтобы включить камеру, пролистните влево"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Пока я не отключу"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядка батареи (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Гость"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"Добавить гостя"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"1 мин."</item> <item quantity="other" msgid="6924190729213550991">"%d мин."</item> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index e917350..9456ebd 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -223,6 +223,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Žiadne nedávne aplikácie"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informácie o aplikácii"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"hľadať"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nabitá"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Nabíja sa"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Úplné nabitie o <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nenabíja sa"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Sieť môže byť\nmonitorovaná"</string> <string name="description_target_search" msgid="3091587249776033139">"Vyhľadávanie"</string> <string name="description_direction_up" msgid="7169032478259485180">"Prejdite prstom nahor: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -241,6 +245,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Fotoaparát otvoríte prejdením prstom doľava"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Dokým túto funkciu nevypnete"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíja sa (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Hosť"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"Pridať hosťa"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Na jednu minútu"</item> <item quantity="other" msgid="6924190729213550991">"Na %d min"</item> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 0b117a1..10ba09f 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Ni nedavnih aplikacij"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Podatki o aplikaciji"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"iskanje"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Akumulator napolnjen"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Polnjenje"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do napolnjenosti"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Se ne polni"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Omrežje je\nlahko spremljano"</string> <string name="description_target_search" msgid="3091587249776033139">"Iskanje"</string> <string name="description_direction_up" msgid="7169032478259485180">"Povlecite navzgor za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Povlecite v levo za fotoaparat"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Dokler tega ne izklopite"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Gost"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"Dodajanje gosta"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Za eno minuto"</item> <item quantity="other" msgid="6924190729213550991">"Za %d min"</item> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 4a49a7b..d9c1cfc 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Нема недавних апликација"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информације о апликацији"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"претражи"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Напуњена је"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Пуњење"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> док се не напуни"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Не пуни се"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежа се можда\nнадгледа"</string> <string name="description_target_search" msgid="3091587249776033139">"Претрага"</string> <string name="description_direction_up" msgid="7169032478259485180">"Превуците нагоре за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Превуците улево за камеру"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Док не искључите"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Пуњење (пун је за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Гост"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Гост"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Један минут"</item> <item quantity="other" msgid="6924190729213550991">"%d мин"</item> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index d2024c4..b802a48 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Inga aktiva appar"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformation"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"sök"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Laddat"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Laddar"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> tills batteriet är fulladdat"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Laddar inte"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nätverket kan\nvara övervakat"</string> <string name="description_target_search" msgid="3091587249776033139">"Sök"</string> <string name="description_direction_up" msgid="7169032478259485180">"Dra uppåt för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Dra åt vänster om du vill visa kameran"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Tills du inaktiverar detta"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laddar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tills batteriet är fulladdat)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Gäst"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"Lägg till gäst"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"I en minut"</item> <item quantity="other" msgid="6924190729213550991">"I %d minuter"</item> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index d42077f..1cd1752 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -219,6 +219,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Hakuna programu za karibuni"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Maelezo ya Programu"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"tafuta"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Betri imejaa"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Inachaji"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> hadi ijae"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Haichaji"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Huenda mtandao\nunafuatiliwa"</string> <string name="description_target_search" msgid="3091587249776033139">"Tafuta"</string> <string name="description_direction_up" msgid="7169032478259485180">"Sogeza juu kwa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string> @@ -237,6 +241,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Telezesha kidole kushoto ili ufikie kamera"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Hadi utakapozima hili"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Inachaji ( <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hadi ijae)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Aliyealikwa"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Aliyealikwa"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Kwa dakika moja"</item> <item quantity="other" msgid="6924190729213550991">"Kwa dakika %d"</item> diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml index 47581a9..9f4c364 100644 --- a/packages/SystemUI/res/values-sw600dp/config.xml +++ b/packages/SystemUI/res/values-sw600dp/config.xml @@ -32,4 +32,7 @@ <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow card. --> <integer name="keyguard_max_notification_count">5</integer> + + <!-- Set to true to enable the user switcher on the keyguard. --> + <bool name="config_keyguardUserSwitcher">true</bool> </resources> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index ee4ba0e..791d5f6 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"ไม่มีแอปล่าสุด"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"ข้อมูลแอปพลิเคชัน"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"ค้นหา"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ชาร์จแล้ว"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"กำลังชาร์จ"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"อีก <xliff:g id="CHARGING_TIME">%s</xliff:g> จึงจะเต็ม"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"ไม่ได้ชาร์จ"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"เครือข่ายอาจ\nถูกตรวจสอบ"</string> <string name="description_target_search" msgid="3091587249776033139">"ค้นหา"</string> <string name="description_direction_up" msgid="7169032478259485180">"เลื่อนขึ้นเพื่อ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"กวาดไปทางซ้ายเพื่อใช้กล้องถ่ายรูป"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"จนกว่าคุณจะปิดฟังก์ชันนี้"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"กำลังชาร์จ (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> เต็ม)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"ผู้เข้าร่วม"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ ผู้เข้าร่วม"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"1 นาที"</item> <item quantity="other" msgid="6924190729213550991">"%d นาที"</item> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 42e168e..42f262b 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Walang kamakailang mga app"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Impormasyon ng Application"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"maghanap"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nasingil na"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Nagcha-charge"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> hanggang mapuno"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Hindi nagcha-charge"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Maaaring\nsinusubaybayan ang network"</string> <string name="description_target_search" msgid="3091587249776033139">"Maghanap"</string> <string name="description_direction_up" msgid="7169032478259485180">"Mag-slide pataas para sa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Mag-swipe pakaliwa para sa camera"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Hanggang sa i-off mo ito"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nagtsa-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang mapuno)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Bisita"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Bisita"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Sa loob ng isang minuto"</item> <item quantity="other" msgid="6924190729213550991">"Sa loob ng %d (na) minuto"</item> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 2967731..fbd8549f 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Yakın zamanda kullanılan uygulama yok"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Uygulama Bilgileri"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"ara"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Ödeme alındı"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Şarj oluyor"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Tam şarj olmasına <xliff:g id="CHARGING_TIME">%s</xliff:g> kaldı"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Şarj olmuyor"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Ağ izleniyor\nolabilir"</string> <string name="description_target_search" msgid="3091587249776033139">"Ara"</string> <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> için yukarı kaydırın."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Kamera için sola kaydırın"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Siz bunu kapatana kadar"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Şarj oluyor (tamamen dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Misafir"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Misafir"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Bir dakika süreyle"</item> <item quantity="other" msgid="6924190729213550991">"%d dakika süreyle"</item> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 43d4146..12dd57e 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Немає останніх додатків"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Інформація про додаток"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"пошук"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Заряджено"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Заряджається"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"До повного зарядження <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Не заряджається"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мережа може\nвідстежуватися"</string> <string name="description_target_search" msgid="3091587249776033139">"Пошук"</string> <string name="description_direction_up" msgid="7169032478259485180">"Проведіть пальцем угору, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Проведіть пальцем ліворуч, щоб скористатися камерою"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Доки ви не вимкнете"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного зарядження)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Гість"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"Додати гостя"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Протягом хвилини"</item> <item quantity="other" msgid="6924190729213550991">"Протягом %d хв"</item> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index eede966..5c24e8b 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Không có ứng dụng nào gần đây"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Thông tin ứng dụng"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"tìm kiếm"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Đã sạc"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Đang sạc"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> cho đến khi đầy"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Hiện không sạc"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mạng có thể\nđược giám sát"</string> <string name="description_target_search" msgid="3091587249776033139">"Tìm kiếm"</string> <string name="description_direction_up" msgid="7169032478259485180">"Trượt lên để <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Vuốt sang trái để mở máy ảnh"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Cho đến khi bạn tắt tính năng này"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Đang sạc (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho đến khi đầy)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Khách"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Khách"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Trong một phút"</item> <item quantity="other" msgid="6924190729213550991">"Trong %d phút"</item> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 61d59ab..f975252 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -223,6 +223,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"最近没有用过任何应用"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"应用信息"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"搜索"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"充电完成"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"正在充电"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"还需<xliff:g id="CHARGING_TIME">%s</xliff:g>才能充满"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"未在充电"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"网络可能会\n受到监控"</string> <string name="description_target_search" msgid="3091587249776033139">"搜索"</string> <string name="description_direction_up" msgid="7169032478259485180">"向上滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string> @@ -241,6 +245,8 @@ <string name="camera_hint" msgid="5241441720959174226">"向左滑动可打开相机"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"直到您将其关闭"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"正在充电(还需<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>才能充满)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"访客"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"添加新访客"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"1分钟"</item> <item quantity="other" msgid="6924190729213550991">"%d分钟"</item> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 8843363..4b5cf08 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -223,6 +223,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"沒有最近使用的應用程式"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資料"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"已完成充電"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"充電中"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g>後完成充電"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"非充電中"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"網絡可能會\n受到監控"</string> <string name="description_target_search" msgid="3091587249776033139">"搜尋"</string> <string name="description_direction_up" msgid="7169032478259485180">"向上滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string> @@ -241,6 +245,8 @@ <string name="camera_hint" msgid="5241441720959174226">"向左快速滑動即可使用相機功能"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"直至您關閉這項設定"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"訪客"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"新增訪客"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"1 分鐘"</item> <item quantity="other" msgid="6924190729213550991">"%d 分鐘"</item> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index a6efe21..a780ad1 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -223,6 +223,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"沒有最近使用的應用程式"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資訊"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"已充飽"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"充電中"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g>後充飽"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"未充電"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"網路可能\n受到監控"</string> <string name="description_target_search" msgid="3091587249776033139">"搜尋"</string> <string name="description_direction_up" msgid="7169032478259485180">"向上滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string> @@ -241,6 +245,8 @@ <string name="camera_hint" msgid="5241441720959174226">"向左滑動可使用相機功能"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"手動關閉這項設定前一律啟用"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後充飽)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"訪客"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"新增訪客"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"1 分鐘"</item> <item quantity="other" msgid="6924190729213550991">"%d 分鐘"</item> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index bfeb47a..8458ca8 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -221,6 +221,10 @@ <string name="recents_empty_message" msgid="7883614615463619450">"Azikho izinhlelo zokusebenza zakamuva"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Ulwazi lohlelo lokusebenza"</string> <string name="recents_search_bar_label" msgid="8074997400187836677">"sesha"</string> + <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Kushajiwe"</string> + <string name="expanded_header_battery_charging" msgid="205623198487189724">"Iyashaja"</string> + <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> ize igcwale"</string> + <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Ayishaji"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Kungenzeka inethiwekhi\niqashiwe"</string> <string name="description_target_search" msgid="3091587249776033139">"Sesha"</string> <string name="description_direction_up" msgid="7169032478259485180">"Shelelisela ngenhla ku-<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -239,6 +243,8 @@ <string name="camera_hint" msgid="5241441720959174226">"Swayiphela ngakwesokunxele ukuze uthole ikhamela"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Uze uvale lokhu"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Iyashaja (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string> + <string name="guest_nickname" msgid="8059989128963789678">"Isihambeli"</string> + <string name="guest_new_guest" msgid="4259024453643879653">"+ Isihambeli"</string> <plurals name="zen_mode_duration_minutes"> <item quantity="one" msgid="9040808414992812341">"Iminithi elilodwa"</item> <item quantity="other" msgid="6924190729213550991">"Amaminithi angu-%d"</item> diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml index c453618..8473d96 100644 --- a/packages/SystemUI/res/values/attrs.xml +++ b/packages/SystemUI/res/values/attrs.xml @@ -54,5 +54,10 @@ <enum name="horizontal" value="0" /> <enum name="vertical" value="1" /> </attr> + <declare-styleable name="UserAvatarView"> + <attr name="frameWidth" format="dimension" /> + <attr name="activeFrameColor" format="color" /> + <attr name="frameColor" /> + </declare-styleable> </resources> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 8c1a9c7..4e38da6 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -46,9 +46,7 @@ <color name="keyguard_overflow_content_color">#ff686868</color> <!-- The default recents task bar background color. --> - <color name="recents_task_bar_default_background_color">#e6444444</color> - <!-- The default recents task bar text color. --> - <color name="recents_task_bar_default_text_color">#ffeeeeee</color> + <color name="recents_task_bar_default_background_color">#ffe6e6e6</color> <!-- The recents task bar light text color to be drawn on top of dark backgrounds. --> <color name="recents_task_bar_light_text_color">#ffeeeeee</color> <!-- The recents task bar dark text color to be drawn on top of light backgrounds. --> @@ -62,6 +60,9 @@ <color name="keyguard_affordance">#ffffffff</color> + <!-- The color of the circle around the primary user in the user switcher --> + <color name="current_user_border_color">@color/primary_color</color> + <!-- Our material color palette (deep teal) --> <color name="primary_color">#ff7fcac3</color> <color name="background_color_1">#ff384248</color> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 1ef5bcd..c1f971a 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -108,17 +108,25 @@ <!-- milliseconds before the heads up notification accepts touches. --> <integer name="heads_up_sensitivity_delay">700</integer> + <!-- The duration in seconds to wait before the dismiss buttons are shown. --> + <integer name="recents_task_bar_dismiss_delay_seconds">1</integer> <!-- The min animation duration for animating views that are currently visible. --> - <integer name="recents_filter_animate_current_views_min_duration">175</integer> + <integer name="recents_filter_animate_current_views_duration">250</integer> <!-- The min animation duration for animating views that are newly visible. --> - <integer name="recents_filter_animate_new_views_min_duration">125</integer> + <integer name="recents_filter_animate_new_views_duration">250</integer> <!-- The min animation duration for animating the task bar in. --> - <integer name="recents_animate_task_bar_enter_duration">250</integer> + <integer name="recents_animate_task_bar_enter_duration">275</integer> <!-- The animation delay for animating the first task in. This should roughly be the animation duration of the transition in to recents. --> <integer name="recents_animate_task_bar_enter_delay">225</integer> <!-- The min animation duration for animating the task bar out. --> + <integer name="recents_animate_task_exit_to_home_duration">225</integer> + <!-- The min animation duration for animating the task bar out. --> <integer name="recents_animate_task_bar_exit_duration">125</integer> + <!-- The min animation duration for animating the task in when transitioning from home. --> + <integer name="recents_animate_task_enter_from_home_duration">275</integer> + <!-- The animation stagger to apply to each task animation when transitioning from home. --> + <integer name="recents_animate_task_enter_from_home_delay">10</integer> <!-- The min animation duration for animating the nav bar scrim in. --> <integer name="recents_nav_bar_scrim_enter_duration">400</integer> <!-- The animation duration for animating the removal of a task view. --> @@ -146,5 +154,8 @@ Notification.tickerText across the status bar for what seems like an eternity. --> <bool name="enable_ticker">false</bool> + + <!-- Set to true to enable the user switcher on the keyguard. --> + <bool name="config_keyguardUserSwitcher">false</bool> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 4a15363..36c1994 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -212,7 +212,7 @@ <dimen name="glowpadview_inner_radius">15dip</dimen> <!-- The size of the application icon in the recents task view. --> - <dimen name="recents_task_view_application_icon_size">32dp</dimen> + <dimen name="recents_task_view_application_icon_size">48dp</dimen> <!-- The size of the activity icon in the recents task view. --> <dimen name="recents_task_view_activity_icon_size">60dp</dimen> @@ -235,9 +235,6 @@ <!-- The amount of highlight to make on each task view. --> <dimen name="recents_task_view_highlight">1dp</dimen> - <!-- The amount of space a user has to scroll to dismiss any info panes. --> - <dimen name="recents_task_stack_scroll_dismiss_info_pane_distance">50dp</dimen> - <!-- The height of the search bar space. --> <dimen name="recents_search_bar_space_height">64dp</dimen> @@ -323,6 +320,9 @@ device. --> <dimen name="unlock_move_distance">75dp</dimen> + <!-- Distance after which the scrim starts fading in when dragging down the quick settings --> + <dimen name="notification_scrim_wait_distance">100dp</dimen> + <!-- Move distance for the unlock hint animation on the lockscreen --> <dimen name="hint_move_distance">75dp</dimen> @@ -335,4 +335,11 @@ <!-- end margin for multi user switch in expanded quick settings --> <dimen name="multi_user_switch_expanded_margin">8dp</dimen> + + <!-- end margin for system icons if multi user switch is hidden --> + <dimen name="system_icons_switcher_hidden_expanded_margin">16dp</dimen> + + <!-- The thickness of the colored border around the current user. --> + <dimen name="keyguard_user_switcher_border_thickness">2dp</dimen> + </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 260f59c..f021253 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -549,6 +549,18 @@ <string name="recents_search_bar_label">search</string> + <!-- Expanded Status Bar Header: Battery Charged [CHAR LIMIT=40] --> + <string name="expanded_header_battery_charged">Charged</string> + + <!-- Expanded Status Bar Header: Charging, no known time [CHAR LIMIT=40] --> + <string name="expanded_header_battery_charging">Charging</string> + + <!-- Expanded Status Bar Header: Charging, showing time left until charged [CHAR LIMIT=40] --> + <string name="expanded_header_battery_charging_with_time"><xliff:g id="charging_time" example="2 hrs 25 min">%s</xliff:g> until full</string> + + <!-- Expanded Status Bar Header: Not charging [CHAR LIMIT=40] --> + <string name="expanded_header_battery_not_charging">Not charging</string> + <!-- Glyph to be overlaid atop the battery when the level is extremely low. Do not translate. --> <string name="battery_meter_very_low_overlay_symbol">!</string> @@ -565,14 +577,6 @@ <!-- Description of the left direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] --> <string name="description_direction_left">"Slide left for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string> - <!-- Zen mode: Summary notification content title. [CHAR LIMIT=NONE] --> - <plurals name="zen_mode_notification_title"> - <item quantity="one">Notification hidden</item> - <item quantity="other">%d notifications hidden</item> - </plurals> - <!-- Zen mode: Summary notification content text. [CHAR LIMIT=NONE] --> - <string name="zen_mode_notification_text">Touch to show</string> - <!-- Zen mode: Short title. [CHAR LIMIT=40] --> <string name="zen_mode_title">Do not disturb</string> @@ -602,6 +606,13 @@ <!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=40]--> <string name="keyguard_indication_charging_time">Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string> + <!-- Related to user switcher --><skip/> + <!-- Name for the guest user --> + <string name="guest_nickname">Guest</string> + + <!-- Label for adding a new guest --> + <string name="guest_new_guest">+ Guest</string> + <!-- Zen mode condition: time duration in minutes. [CHAR LIMIT=NONE] --> <plurals name="zen_mode_duration_minutes"> <item quantity="one">For one minute</item> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 79a13f8..e5d5b03 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -70,17 +70,29 @@ <style name="TextAppearance.StatusBar.Expanded" parent="@*android:style/TextAppearance.StatusBar" /> <style name="TextAppearance.StatusBar.Expanded.Clock"> - <item name="android:textSize">18dp</item> + <item name="android:textSize">16dp</item> <item name="android:textStyle">normal</item> <item name="android:textColor">#ffffff</item> </style> <style name="TextAppearance.StatusBar.Expanded.Date"> + <item name="android:textSize">14dp</item> + <item name="android:textStyle">normal</item> + <item name="android:textColor">#99ffffff</item> + </style> + + <style name="TextAppearance.StatusBar.Expanded.AboveDateTime"> <item name="android:textSize">12dp</item> <item name="android:textStyle">normal</item> - <item name="android:textColor">#afb3b6</item> + <item name="android:textColor">#99ffffff</item> </style> + <style name="TextAppearance.StatusBar.Expanded.EmergencyCallsOnly" + parent="TextAppearance.StatusBar.Expanded.AboveDateTime" /> + + <style name="TextAppearance.StatusBar.Expanded.ChargingInfo" + parent="TextAppearance.StatusBar.Expanded.AboveDateTime" /> + <style name="TextAppearance.StatusBar.Expanded.Network" parent="@style/TextAppearance.StatusBar.Expanded.Date"> <item name="android:textColor">#999999</item> </style> @@ -88,6 +100,13 @@ <style name="TextAppearance.StatusBar.Expanded.Network.EmergencyOnly"> </style> + <style name="TextAppearance.StatusBar.Expanded.UserSwitcher"> + <item name="android:textSize">16sp</item> + <item name="android:textStyle">normal</item> + <item name="android:textColor">#ffffff</item> + </style> + <style name="TextAppearance.StatusBar.Expanded.UserSwitcher.UserName" /> + <style name="TextAppearance" /> <style name="TextAppearance.QuickSettings" /> diff --git a/packages/SystemUI/src/com/android/systemui/DessertCaseView.java b/packages/SystemUI/src/com/android/systemui/DessertCaseView.java index 4147155..14392b4 100644 --- a/packages/SystemUI/src/com/android/systemui/DessertCaseView.java +++ b/packages/SystemUI/src/com/android/systemui/DessertCaseView.java @@ -507,7 +507,6 @@ public class DessertCaseView extends FrameLayout { | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY ); } diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java index 7c85712..9650435 100644 --- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java +++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java @@ -20,9 +20,14 @@ import android.view.Display; import android.view.View; public interface RecentsComponent { + public interface Callbacks { + public void onVisibilityChanged(boolean visible); + } + void showRecents(boolean triggeredFromAltTab, View statusBarView); void hideRecents(boolean triggeredFromAltTab); void toggleRecents(Display display, int layoutDirection, View statusBarView); void preloadRecents(); void cancelPreloadingRecents(); + void setCallback(Callbacks cb); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index c006c88..b9e2e1b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -59,8 +59,6 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.MultiUserAvatarCache; import com.android.keyguard.ViewMediatorCallback; -import com.android.keyguard.analytics.KeyguardAnalytics; -import com.android.keyguard.analytics.Session; import com.android.systemui.SystemUI; import com.android.systemui.statusbar.phone.PhoneStatusBar; import com.android.systemui.statusbar.phone.ScrimController; @@ -70,7 +68,6 @@ import com.android.systemui.statusbar.phone.StatusBarWindowManager; import java.io.File; import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; -import static com.android.keyguard.analytics.KeyguardAnalytics.SessionTypeAdapter; /** @@ -117,7 +114,6 @@ import static com.android.keyguard.analytics.KeyguardAnalytics.SessionTypeAdapte public class KeyguardViewMediator extends SystemUI { private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000; final static boolean DEBUG = false; - private static final boolean ENABLE_ANALYTICS = false; private final static boolean DBG_WAKE = false; private final static String TAG = "KeyguardViewMediator"; @@ -199,8 +195,6 @@ public class KeyguardViewMediator extends SystemUI { private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; - private KeyguardAnalytics mKeyguardAnalytics; - // these are protected by synchronized (this) /** @@ -245,6 +239,12 @@ public class KeyguardViewMediator extends SystemUI { private String mPhoneState = TelephonyManager.EXTRA_STATE_IDLE; /** + * Whether a hide is pending an we are just waiting for #startKeyguardExitAnimation to be + * called. + * */ + private boolean mHiding; + + /** * we send this intent when the keyguard is dismissed. */ private static final Intent USER_PRESENT_INTENT = new Intent(Intent.ACTION_USER_PRESENT) @@ -469,22 +469,6 @@ public class KeyguardViewMediator extends SystemUI { mViewMediatorCallback, mLockPatternUtils); final ContentResolver cr = mContext.getContentResolver(); - if (ENABLE_ANALYTICS && !LockPatternUtils.isSafeModeEnabled() && - Settings.Secure.getInt(cr, KEYGUARD_ANALYTICS_SETTING, 0) == 1) { - mKeyguardAnalytics = new KeyguardAnalytics(mContext, new SessionTypeAdapter() { - - @Override - public int getSessionType() { - return mLockPatternUtils.isSecure() && !mUpdateMonitor.getUserHasTrust( - mLockPatternUtils.getCurrentUser()) - ? Session.TYPE_KEYGUARD_SECURE - : Session.TYPE_KEYGUARD_INSECURE; - } - }, new File(mContext.getCacheDir(), "keyguard_analytics.bin")); - } else { - mKeyguardAnalytics = null; - } - mScreenOn = mPM.isScreenOn(); mLockSounds = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0); @@ -585,9 +569,6 @@ public class KeyguardViewMediator extends SystemUI { } else { doKeyguardLocked(null); } - if (ENABLE_ANALYTICS && mKeyguardAnalytics != null) { - mKeyguardAnalytics.getCallback().onScreenOff(); - } } KeyguardUpdateMonitor.getInstance(mContext).dispatchScreenTurndOff(why); } @@ -830,9 +811,6 @@ public class KeyguardViewMediator extends SystemUI { updateActivityLockScreenState(); adjustStatusBarLocked(); } - if (ENABLE_ANALYTICS && mKeyguardAnalytics != null) { - mKeyguardAnalytics.getCallback().onSetOccluded(isOccluded); - } } } @@ -1197,6 +1175,7 @@ public class KeyguardViewMediator extends SystemUI { } mStatusBarKeyguardViewManager.show(options); + mHiding = false; mShowing = true; mKeyguardDonePending = false; updateActivityLockScreenState(); @@ -1219,7 +1198,7 @@ public class KeyguardViewMediator extends SystemUI { synchronized (KeyguardViewMediator.this) { if (DEBUG) Log.d(TAG, "handleHide"); try { - + mHiding = true; if (mShowing) { // Don't actually hide the Keyguard at the moment, wait for window manager until @@ -1240,6 +1219,11 @@ public class KeyguardViewMediator extends SystemUI { private void handleStartKeyguardExitAnimation(long startTime, long fadeoutDuration) { synchronized (KeyguardViewMediator.this) { + if (!mHiding) { + return; + } + mHiding = false; + // only play "unlock" noises if not on a call (since the incall UI // disables the keyguard) if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState)) { diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java index e8f3745..41b1f75 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java @@ -126,7 +126,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { } private void updateNotification() { - Slog.d(TAG, "updateNotification mWarning=" + mWarning + if (DEBUG) Slog.d(TAG, "updateNotification mWarning=" + mWarning + " mSaver=" + mSaver + " mInvalidCharger=" + mInvalidCharger); if (mInvalidCharger) { showInvalidChargerNotification(); @@ -152,6 +152,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { .setContentText(mContext.getString(R.string.invalid_charger_text)) .setPriority(Notification.PRIORITY_MAX) .setCategory(Notification.CATEGORY_SYSTEM) + .setVisibility(Notification.VISIBILITY_PUBLIC) .setFullScreenIntent(pendingBroadcast(ACTION_SHOW_FALLBACK_CHARGER), true); final Notification n = nb.build(); if (n.headsUpContentView != null) { @@ -171,6 +172,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { .setOngoing(true) .setPriority(Notification.PRIORITY_MAX) .setCategory(Notification.CATEGORY_SYSTEM) + .setVisibility(Notification.VISIBILITY_PUBLIC) .setFullScreenIntent(pendingBroadcast(ACTION_SHOW_FALLBACK_WARNING), true); if (hasBatterySettings()) { nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SETTINGS)); @@ -197,7 +199,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { .setContentText(mContext.getString(R.string.battery_saver_notification_text)) .setOngoing(true) .setShowWhen(false) - .setCategory(Notification.CATEGORY_SYSTEM); + .setCategory(Notification.CATEGORY_SYSTEM) + .setVisibility(Notification.VISIBILITY_PUBLIC); if (hasSaverSettings()) { nb.addAction(0, mContext.getString(R.string.battery_saver_notification_action_text), @@ -238,13 +241,13 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { @Override public void dismissLowBatteryWarning() { - Slog.i(TAG, "dismissing low battery warning: level=" + mBatteryLevel); + if (DEBUG) Slog.d(TAG, "dismissing low battery warning: level=" + mBatteryLevel); dismissLowBatteryNotification(); mFallbackDialogs.dismissLowBatteryWarning(); } private void dismissLowBatteryNotification() { - Slog.i(TAG, "dismissing low battery notification"); + if (mWarning) Slog.i(TAG, "dismissing low battery notification"); mWarning = false; updateNotification(); } @@ -307,7 +310,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { } private void dismissInvalidChargerNotification() { - Slog.i(TAG, "dismissing invalid charger notification"); + if (mInvalidCharger) Slog.i(TAG, "dismissing invalid charger notification"); mInvalidCharger = false; updateNotification(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java index b981ed6..c4bdb19 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java @@ -69,6 +69,7 @@ public class NotificationsTile extends QSTile<NotificationsTile.NotificationsSta @Override public void onViewAttachedToWindow(View v) { + vp.updateStates(); volumeComponent.setVolumePanel(vp); } }); diff --git a/packages/SystemUI/src/com/android/systemui/recent/Recents.java b/packages/SystemUI/src/com/android/systemui/recent/Recents.java index 116d755..e03c01c 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recent/Recents.java @@ -273,6 +273,13 @@ public class Recents extends SystemUI implements RecentsComponent { } } + @Override + public void setCallback(Callbacks cb) { + if (mUseAlternateRecents) { + mAlternateRecents.setRecentsComponentCallback(cb); + } + } + /** * Send broadcast only if BOOT_COMPLETED */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java index 24a31f8..8dcdcdb 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java @@ -27,7 +27,6 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; -import android.graphics.Matrix; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; @@ -35,16 +34,13 @@ import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; -import android.os.SystemClock; import android.os.UserHandle; -import android.util.DisplayMetrics; -import android.view.Display; -import android.view.Surface; -import android.view.SurfaceControl; import android.view.View; import android.view.WindowManager; import com.android.systemui.R; +import com.android.systemui.RecentsComponent; +import java.lang.ref.WeakReference; import java.util.Iterator; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -129,8 +125,10 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta final public static int MSG_TOGGLE_RECENTS = 6; final public static int MSG_START_ENTER_ANIMATION = 7; - final public static String EXTRA_ANIMATING_WITH_THUMBNAIL = "recents.animatingWithThumbnail"; - final public static String EXTRA_FROM_ALT_TAB = "recents.triggeredFromAltTab"; + final public static String EXTRA_FROM_HOME = "recents.triggeredOverHome"; + final public static String EXTRA_FROM_APP_THUMBNAIL = "recents.animatingWithThumbnail"; + final public static String EXTRA_FROM_APP_FULL_SCREENSHOT = "recents.thumbnail"; + final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "recents.triggeredFromAltTab"; final public static String KEY_CONFIGURATION_DATA = "recents.data.updateForConfiguration"; final public static String KEY_WINDOW_RECT = "recents.windowRect"; final public static String KEY_SYSTEM_INSETS = "recents.systemInsets"; @@ -138,7 +136,6 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta final public static String KEY_TWO_TASK_STACK_RECT = "recents.twoCountTaskRect"; final public static String KEY_MULTIPLE_TASK_STACK_RECT = "recents.multipleCountTaskRect"; - final static int sMinToggleDelay = 425; final static String sToggleRecentsAction = "com.android.systemui.recents.SHOW_RECENTS"; @@ -146,6 +143,9 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta final static String sRecentsActivity = "com.android.systemui.recents.RecentsActivity"; final static String sRecentsService = "com.android.systemui.recents.RecentsService"; + static Bitmap sLastScreenshot; + static RecentsComponent.Callbacks sRecentsComponentCallbacks; + Context mContext; SystemServicesProxy mSystemServicesProxy; @@ -213,15 +213,19 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta if (Console.Enabled) { Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|hideRecents]"); } + if (mServiceIsBound && mBootCompleted) { - // Notify recents to close it - try { - Bundle data = new Bundle(); - Message msg = Message.obtain(null, MSG_HIDE_RECENTS, triggeredFromAltTab ? 1 : 0, 0); - msg.setData(data); - mService.send(msg); - } catch (RemoteException re) { - re.printStackTrace(); + if (isRecentsTopMost(null)) { + // Notify recents to close it + try { + Bundle data = new Bundle(); + Message msg = Message.obtain(null, MSG_HIDE_RECENTS, + triggeredFromAltTab ? 1 : 0, 0); + msg.setData(data); + mService.send(msg); + } catch (RemoteException re) { + re.printStackTrace(); + } } } } @@ -343,80 +347,6 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta } } - /** Converts from the device rotation to the degree */ - float getDegreesForRotation(int value) { - switch (value) { - case Surface.ROTATION_90: - return 360f - 90f; - case Surface.ROTATION_180: - return 360f - 180f; - case Surface.ROTATION_270: - return 360f - 270f; - } - return 0f; - } - - /** Takes a screenshot of the surface */ - Bitmap takeScreenshot(Display display) { - DisplayMetrics dm = new DisplayMetrics(); - display.getRealMetrics(dm); - float[] dims = {dm.widthPixels, dm.heightPixels}; - float degrees = getDegreesForRotation(display.getRotation()); - boolean requiresRotation = (degrees > 0); - if (requiresRotation) { - // Get the dimensions of the device in its native orientation - Matrix m = new Matrix(); - m.preRotate(-degrees); - m.mapPoints(dims); - dims[0] = Math.abs(dims[0]); - dims[1] = Math.abs(dims[1]); - } - return SurfaceControl.screenshot((int) dims[0], (int) dims[1]); - } - - /** Creates the activity options for a thumbnail transition. */ - ActivityOptions getThumbnailTransitionActivityOptions(Rect taskRect) { - // Loading from thumbnail - Bitmap thumbnail; - Bitmap firstThumbnail = loadFirstTaskThumbnail(); - if (firstThumbnail != null) { - // Create the thumbnail - thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(), - Bitmap.Config.ARGB_8888); - int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight()); - Canvas c = new Canvas(thumbnail); - c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size), - new Rect(0, 0, taskRect.width(), taskRect.height()), null); - c.setBitmap(null); - // Recycle the old thumbnail - firstThumbnail.recycle(); - } else { - // Load the thumbnail from the screenshot if can't get one from the system - WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); - Display display = wm.getDefaultDisplay(); - Bitmap screenshot = takeScreenshot(display); - if (screenshot != null) { - Resources res = mContext.getResources(); - int size = Math.min(screenshot.getWidth(), screenshot.getHeight()); - int statusBarHeight = res.getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height); - thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(), - Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(thumbnail); - c.drawBitmap(screenshot, new Rect(0, statusBarHeight, size, statusBarHeight + - size), new Rect(0, 0, taskRect.width(), taskRect.height()), null); - c.setBitmap(null); - // Recycle the temporary screenshot - screenshot.recycle(); - } else { - return null; - } - } - - return ActivityOptions.makeThumbnailScaleDownAnimation(mStatusBarView, thumbnail, - taskRect.left, taskRect.top, this); - } - /** Returns whether the recents is currently running */ boolean isRecentsTopMost(AtomicBoolean isHomeTopMost) { SystemServicesProxy ssp = mSystemServicesProxy; @@ -462,10 +392,12 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta mService.send(msg); // Time this path - Console.logTraceTime(Constants.Log.App.TimeRecentsStartup, - Constants.Log.App.TimeRecentsStartupKey, "sendToggleRecents"); - Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask, - Constants.Log.App.TimeRecentsLaunchKey, "sendToggleRecents"); + if (Console.Enabled) { + Console.logTraceTime(Constants.Log.App.TimeRecentsStartup, + Constants.Log.App.TimeRecentsStartupKey, "sendToggleRecents"); + Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask, + Constants.Log.App.TimeRecentsLaunchKey, "sendToggleRecents"); + } } catch (RemoteException re) { re.printStackTrace(); } @@ -486,6 +418,68 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta } } + /** + * Creates the activity options for a unknown state->recents transition. + */ + ActivityOptions getUnknownTransitionActivityOptions() { + // Reset the last screenshot + consumeLastScreenshot(); + return ActivityOptions.makeCustomAnimation(mContext, + R.anim.recents_from_unknown_enter, + R.anim.recents_from_unknown_exit, mHandler, this); + } + + /** + * Creates the activity options for a home->recents transition. + */ + ActivityOptions getHomeTransitionActivityOptions() { + // Reset the last screenshot + consumeLastScreenshot(); + return ActivityOptions.makeCustomAnimation(mContext, + R.anim.recents_from_launcher_enter, + R.anim.recents_from_launcher_exit, mHandler, this); + } + + /** + * Creates the activity options for an app->recents transition. If this method sets the static + * screenshot, then we will use that for the transition. + */ + ActivityOptions getThumbnailTransitionActivityOptions(Rect taskRect) { + // Recycle the last screenshot + consumeLastScreenshot(); + + // Take the full screenshot + if (Constants.DebugFlags.App.EnableScreenshotAppTransition) { + sLastScreenshot = mSystemServicesProxy.takeScreenshot(); + if (sLastScreenshot != null) { + return ActivityOptions.makeCustomAnimation(mContext, + R.anim.recents_from_app_enter, + R.anim.recents_from_app_exit, mHandler, this); + } + } + + // If the screenshot fails, then load the first task thumbnail and use that + Bitmap firstThumbnail = loadFirstTaskThumbnail(); + if (firstThumbnail != null) { + // Create the new thumbnail for the animation down + // XXX: We should find a way to optimize this so we don't need to create a new bitmap + Bitmap thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(), + Bitmap.Config.ARGB_8888); + int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight()); + Canvas c = new Canvas(thumbnail); + c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size), + new Rect(0, 0, taskRect.width(), taskRect.height()), null); + c.setBitmap(null); + // Recycle the old thumbnail + firstThumbnail.recycle(); + return ActivityOptions.makeThumbnailScaleDownAnimation(mStatusBarView, + thumbnail, taskRect.left, taskRect.top, this); + } + + // If both the screenshot and thumbnail fails, then just fall back to the default transition + return getUnknownTransitionActivityOptions(); + } + /** Starts the recents activity */ void startRecentsActivity(boolean isTopTaskHome) { // If Recents is not the front-most activity and we should animate into it. If @@ -498,39 +492,52 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta Rect taskRect = getAnimationTaskRect(recentTasks); boolean useThumbnailTransition = !isTopTaskHome && hasValidTaskRects(); + boolean hasRecentTasks = !recentTasks.isEmpty(); if (useThumbnailTransition) { // Try starting with a thumbnail transition ActivityOptions opts = getThumbnailTransitionActivityOptions(taskRect); if (opts != null) { - startAlternateRecentsActivity(opts, true); + if (sLastScreenshot != null) { + startAlternateRecentsActivity(opts, EXTRA_FROM_APP_FULL_SCREENSHOT); + } else { + startAlternateRecentsActivity(opts, EXTRA_FROM_APP_THUMBNAIL); + } } else { // Fall through below to the non-thumbnail transition useThumbnailTransition = false; } + } else { + // If there is no thumbnail transition, but is launching from home into recents, then + // use a quick home transition and do the animation from home + if (hasRecentTasks && Constants.DebugFlags.App.EnableHomeTransition) { + ActivityOptions opts = getHomeTransitionActivityOptions(); + startAlternateRecentsActivity(opts, EXTRA_FROM_HOME); + } else { + // Otherwise we do the normal fade from an unknown source + ActivityOptions opts = getUnknownTransitionActivityOptions(); + startAlternateRecentsActivity(opts, null); + } } - // If there is no thumbnail transition, then just use a generic transition - if (!useThumbnailTransition) { - ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, - R.anim.recents_from_launcher_enter, - R.anim.recents_from_launcher_exit, mHandler, this); - startAlternateRecentsActivity(opts, false); + if (Console.Enabled) { + Console.logTraceTime(Constants.Log.App.TimeRecentsStartup, + Constants.Log.App.TimeRecentsStartupKey, "startRecentsActivity"); } - - Console.logTraceTime(Constants.Log.App.TimeRecentsStartup, - Constants.Log.App.TimeRecentsStartupKey, "startRecentsActivity"); mLastToggleTime = System.currentTimeMillis(); } /** Starts the recents activity */ - void startAlternateRecentsActivity(ActivityOptions opts, boolean animatingWithThumbnail) { + void startAlternateRecentsActivity(ActivityOptions opts, String extraFlag) { Intent intent = new Intent(sToggleRecentsAction); intent.setClassName(sRecentsPackage, sRecentsActivity); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - intent.putExtra(EXTRA_ANIMATING_WITH_THUMBNAIL, animatingWithThumbnail); - intent.putExtra(EXTRA_FROM_ALT_TAB, mTriggeredFromAltTab); + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + | Intent.FLAG_ACTIVITY_TASK_ON_HOME); + if (extraFlag != null) { + intent.putExtra(extraFlag, true); + } + intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, mTriggeredFromAltTab); if (opts != null) { mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle( UserHandle.USER_CURRENT)); @@ -539,6 +546,30 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta } } + /** Returns the last screenshot taken, this will be called by the RecentsActivity. */ + public static Bitmap getLastScreenshot() { + return sLastScreenshot; + } + + /** Recycles the last screenshot taken, this will be called by the RecentsActivity. */ + public static void consumeLastScreenshot() { + if (sLastScreenshot != null) { + sLastScreenshot.recycle(); + sLastScreenshot = null; + } + } + + /** Sets the RecentsComponent callbacks. */ + public void setRecentsComponentCallback(RecentsComponent.Callbacks cb) { + sRecentsComponentCallbacks = cb; + } + + /** Notifies the callbacks that the visibility of Recents has changed. */ + public static void notifyVisibilityChanged(boolean visible) { + if (sRecentsComponentCallbacks != null) { + sRecentsComponentCallbacks.onVisibilityChanged(visible); + } + } /**** OnAnimationStartedListener Implementation ****/ diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java index 147ff62..2abbad5 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java @@ -25,10 +25,16 @@ public class Constants { public static final boolean Verbose = false; public static class App { + // Enables the home->Recents transition + public static final boolean EnableHomeTransition = true; + // Enables the screenshot app->Recents transition + public static final boolean EnableScreenshotAppTransition = false; // Enables the filtering of tasks according to their grouping - public static final boolean EnableTaskFiltering = false; + public static final boolean EnableTaskFiltering = true; // Enables clipping of tasks against each other public static final boolean EnableTaskStackClipping = true; + // Enables tapping on the TaskBar to launch the task + public static final boolean EnableTaskBarTouchEvents = true; // Enables the use of theme colors as the task bar background public static final boolean EnableTaskBarThemeColors = true; // Enables app-info pane on long-pressing the icon @@ -44,7 +50,7 @@ public class Constants { // For debugging, this defines the number of mock recents packages to create public static final int SystemServicesProxyMockPackageCount = 3; // For debugging, this defines the number of mock recents tasks to create - public static final int SystemServicesProxyMockTaskCount = 75; + public static final int SystemServicesProxyMockTaskCount = 100; } } @@ -52,8 +58,11 @@ public class Constants { public static class App { public static final String TimeRecentsStartupKey = "startup"; public static final String TimeRecentsLaunchKey = "launchTask"; - public static final boolean TimeRecentsStartup = false; - public static final boolean TimeRecentsLaunchTask = false; + public static final String TimeRecentsScreenshotTransitionKey = "screenshot"; + public static final boolean TimeRecentsStartup = true; + public static final boolean TimeRecentsLaunchTask = true; + public static final boolean TimeRecentsScreenshotTransition = true; + public static final boolean RecentsComponent = false; public static final boolean TaskDataLoader = false; diff --git a/packages/SystemUI/src/com/android/systemui/recents/DozeTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/DozeTrigger.java new file mode 100644 index 0000000..f0b2cb6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/DozeTrigger.java @@ -0,0 +1,85 @@ +/* + * 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.recents; + +import android.os.Handler; + +/** + * A dozer is a class that fires a trigger after it falls asleep. You can occasionally poke it to + * wake it up, but it will fall asleep if left untouched. + */ +public class DozeTrigger { + + Handler mHandler; + + boolean mIsDozing; + boolean mHasTriggered; + int mDozeDurationSeconds; + Runnable mSleepRunnable; + + // Sleep-runnable + Runnable mDozeRunnable = new Runnable() { + @Override + public void run() { + mSleepRunnable.run(); + mIsDozing = false; + mHasTriggered = true; + } + }; + + public DozeTrigger(int dozeDurationSeconds, Runnable sleepRunnable) { + mHandler = new Handler(); + mDozeDurationSeconds = dozeDurationSeconds; + mSleepRunnable = sleepRunnable; + } + + /** Starts dozing. This also resets the trigger flag. */ + public void startDozing() { + forcePoke(); + mHasTriggered = false; + } + + /** Stops dozing. */ + public void stopDozing() { + mHandler.removeCallbacks(mDozeRunnable); + mIsDozing = false; + } + + /** Poke this dozer to wake it up for a little bit, if it is dozing. */ + public void poke() { + if (mIsDozing) { + forcePoke(); + } + } + + /** Poke this dozer to wake it up for a little bit. */ + void forcePoke() { + mHandler.removeCallbacks(mDozeRunnable); + mHandler.postDelayed(mDozeRunnable, mDozeDurationSeconds * 1000); + mIsDozing = true; + } + + /** Returns whether we are dozing or not. */ + public boolean isDozing() { + return mIsDozing; + } + + /** Returns whether the trigger has fired at least once. */ + public boolean hasTriggered() { + return mHasTriggered; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 96344d5..52a17df 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -17,80 +17,94 @@ package com.android.systemui.recents; import android.app.Activity; -import android.appwidget.AppWidgetHost; +import android.app.ActivityOptions; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.res.Configuration; import android.os.Bundle; +import android.os.UserHandle; import android.util.Pair; -import android.view.Gravity; import android.view.KeyEvent; -import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.widget.FrameLayout; +import android.view.ViewStub; import com.android.systemui.R; import com.android.systemui.recents.model.SpaceNode; import com.android.systemui.recents.model.TaskStack; +import com.android.systemui.recents.views.FullscreenTransitionOverlayView; import com.android.systemui.recents.views.RecentsView; +import com.android.systemui.recents.views.SystemBarScrimViews; +import com.android.systemui.recents.views.ViewAnimation; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Set; - -/** Our special app widget host */ -class RecentsAppWidgetHost extends AppWidgetHost { - /* Callbacks to notify when an app package changes */ - interface RecentsAppWidgetHostCallbacks { - public void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo); - } - - RecentsAppWidgetHostCallbacks mCb; - - public RecentsAppWidgetHost(Context context, int hostId, RecentsAppWidgetHostCallbacks cb) { - super(context, hostId); - mCb = cb; - } - - @Override - protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) { - mCb.onProviderChanged(appWidgetId, appWidget); - } -} /* Activity */ public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks, - RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks { - FrameLayout mContainerView; + RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks, + FullscreenTransitionOverlayView.FullScreenTransitionViewCallbacks { + RecentsView mRecentsView; + SystemBarScrimViews mScrimViews; + ViewStub mEmptyViewStub; View mEmptyView; - View mNavBarScrimView; + ViewStub mFullscreenOverlayStub; + FullscreenTransitionOverlayView mFullScreenOverlayView; - AppWidgetHost mAppWidgetHost; + RecentsConfiguration mConfig; + + RecentsAppWidgetHost mAppWidgetHost; AppWidgetProviderInfo mSearchAppWidgetInfo; AppWidgetHostView mSearchAppWidgetHostView; boolean mVisible; boolean mTaskLaunched; - private static Method sPropertyMethod; - static { - try { - Class<?> c = Class.forName("android.view.GLES20Canvas"); - sPropertyMethod = c.getDeclaredMethod("setProperty", String.class, String.class); - if (!sPropertyMethod.isAccessible()) sPropertyMethod.setAccessible(true); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); + // Runnables to finish the Recents activity + FinishRecentsRunnable mFinishRunnable = new FinishRecentsRunnable(true); + FinishRecentsRunnable mFinishWithoutAnimationRunnable = new FinishRecentsRunnable(false); + FinishRecentsRunnable mFinishLaunchHomeRunnable; + + /** + * A Runnable to finish Recents either with/without a transition, and either by calling finish() + * or just launching the specified intent. + */ + class FinishRecentsRunnable implements Runnable { + boolean mUseCustomFinishTransition; + Intent mLaunchIntent; + ActivityOptions mLaunchOpts; + + public FinishRecentsRunnable(boolean withTransition) { + mUseCustomFinishTransition = withTransition; + } + + public FinishRecentsRunnable(Intent launchIntent, ActivityOptions opts) { + mLaunchIntent = launchIntent; + mLaunchOpts = opts; + } + + @Override + public void run() { + // Mark Recents as no longer visible + AlternateRecentsComponent.notifyVisibilityChanged(false); + // Finish Recents + if (mLaunchIntent != null) { + if (mLaunchOpts != null) { + startActivityAsUser(mLaunchIntent, new UserHandle(UserHandle.USER_CURRENT)); + } else { + startActivityAsUser(mLaunchIntent, mLaunchOpts.toBundle(), + new UserHandle(UserHandle.USER_CURRENT)); + } + } else { + finish(); + if (mUseCustomFinishTransition) { + overridePendingTransition(R.anim.recents_to_launcher_enter, + R.anim.recents_to_launcher_exit); + } + } } } @@ -108,8 +122,15 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // Dismiss recents, launching the focused task dismissRecentsIfVisible(); } else { - // Otherwise, just finish the activity without launching any other activities - finish(); + // If we are mid-animation into Recents, then reverse it and finish + if (mFullScreenOverlayView == null || + !mFullScreenOverlayView.cancelAnimateOnEnterRecents(mFinishRunnable)) { + // Otherwise, either finish Recents, or launch Home directly + ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(context, + null, mFinishLaunchHomeRunnable, null); + mRecentsView.startExitToHomeAnimation( + new ViewAnimation.TaskViewExitContext(exitTrigger)); + } } } else if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) { // Try and unfilter and filtered stacks @@ -119,7 +140,9 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } } else if (action.equals(RecentsService.ACTION_START_ENTER_ANIMATION)) { // Try and start the enter animation (or restart it on configuration changed) - mRecentsView.startOnEnterAnimation(); + mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(mFullScreenOverlayView)); + // Call our callback + onEnterAnimationTriggered(); } } }; @@ -128,19 +151,12 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - finish(); + mFinishWithoutAnimationRunnable.run(); } }; /** Updates the set of recent tasks */ void updateRecentsTasks(Intent launchIntent) { - // Update the configuration based on the launch intent - RecentsConfiguration config = RecentsConfiguration.getInstance(); - config.launchedWithThumbnailAnimation = launchIntent.getBooleanExtra( - AlternateRecentsComponent.EXTRA_ANIMATING_WITH_THUMBNAIL, false); - config.launchedFromAltTab = launchIntent.getBooleanExtra( - AlternateRecentsComponent.EXTRA_FROM_ALT_TAB, false); - RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); SpaceNode root = loader.reload(this, Constants.Values.RecentsTaskLoader.PreloadFirstTasksCount); ArrayList<TaskStack> stacks = root.getStacks(); @@ -148,24 +164,34 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView mRecentsView.setBSP(root); } - // Hide the scrim by default when we enter recents - mNavBarScrimView.setVisibility(View.INVISIBLE); + // Update the configuration based on the launch intent + mConfig.launchedFromHome = launchIntent.getBooleanExtra( + AlternateRecentsComponent.EXTRA_FROM_HOME, false); + mConfig.launchedFromAppWithThumbnail = launchIntent.getBooleanExtra( + AlternateRecentsComponent.EXTRA_FROM_APP_THUMBNAIL, false); + mConfig.launchedFromAppWithScreenshot = launchIntent.getBooleanExtra( + AlternateRecentsComponent.EXTRA_FROM_APP_FULL_SCREENSHOT, false); + mConfig.launchedWithAltTab = launchIntent.getBooleanExtra( + AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false); + mConfig.launchedWithNoRecentTasks = !root.hasTasks(); + + // Show the scrim if we animate into Recents without window transitions + mScrimViews.prepareEnterRecentsAnimation(); // Add the default no-recents layout - if (stacks.size() == 1 && stacks.get(0).getTaskCount() == 0) { + if (mEmptyView == null) { + mEmptyView = mEmptyViewStub.inflate(); + } + if (mConfig.launchedWithNoRecentTasks) { mEmptyView.setVisibility(View.VISIBLE); } else { mEmptyView.setVisibility(View.GONE); } - - // Dim the background - mRecentsView.setBackgroundColor(0x80000000); } /** Attempts to allocate and bind the search bar app widget */ void bindSearchBarAppWidget() { if (Constants.DebugFlags.App.EnableSearchLayout) { - RecentsConfiguration config = RecentsConfiguration.getInstance(); SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy(); // Reset the host view and widget info @@ -173,7 +199,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView mSearchAppWidgetInfo = null; // Try and load the app widget id from the settings - int appWidgetId = config.searchBarAppWidgetId; + int appWidgetId = mConfig.searchBarAppWidgetId; if (appWidgetId >= 0) { mSearchAppWidgetInfo = ssp.getAppWidgetInfo(appWidgetId); if (mSearchAppWidgetInfo == null) { @@ -203,7 +229,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } // Save the app widget id into the settings - config.updateSearchBarAppWidgetId(this, widgetInfo.first); + mConfig.updateSearchBarAppWidgetId(this, widgetInfo.first); mSearchAppWidgetInfo = widgetInfo.second; } } @@ -213,8 +239,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView /** Creates the search bar app widget view */ void addSearchBarAppWidgetView() { if (Constants.DebugFlags.App.EnableSearchLayout) { - RecentsConfiguration config = RecentsConfiguration.getInstance(); - int appWidgetId = config.searchBarAppWidgetId; + int appWidgetId = mConfig.searchBarAppWidgetId; if (appWidgetId >= 0) { if (Console.Enabled) { Console.log(Constants.Log.App.SystemUIHandshake, @@ -240,9 +265,24 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView /** Dismisses recents if we are already visible and the intent is to toggle the recents view */ boolean dismissRecentsIfVisible() { if (mVisible) { - if (!mRecentsView.launchFocusedTask()) { - if (!mRecentsView.launchFirstTask()) { - finish(); + // If we are mid-animation into Recents, then reverse it and finish + if (mFullScreenOverlayView == null || + !mFullScreenOverlayView.cancelAnimateOnEnterRecents(mFinishRunnable)) { + // If we have a focused task, then launch that task + if (!mRecentsView.launchFocusedTask()) { + if (mConfig.launchedFromHome) { + // Just start the animation out of recents + ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this, + null, mFinishLaunchHomeRunnable, null); + mRecentsView.startExitToHomeAnimation( + new ViewAnimation.TaskViewExitContext(exitTrigger)); + } else { + // Otherwise, try and launch the first task + if (!mRecentsView.launchFirstTask()) { + // If there are no tasks, then just finish recents + mFinishLaunchHomeRunnable.run(); + } + } } } return true; @@ -264,38 +304,41 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // Initialize the loader and the configuration RecentsTaskLoader.initialize(this); - RecentsConfiguration.reinitialize(this); + mConfig = RecentsConfiguration.reinitialize(this); + + // Create the home intent runnable + Intent homeIntent = new Intent(Intent.ACTION_MAIN, null); + homeIntent.addCategory(Intent.CATEGORY_HOME); + homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | + Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent, + ActivityOptions.makeCustomAnimation(this, R.anim.recents_to_launcher_enter, + R.anim.recents_to_launcher_exit)); // Initialize the widget host (the host id is static and does not change) - mAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId, this); + mAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId); - // Create the view hierarchy - mRecentsView = new RecentsView(this); + // Set the Recents layout + setContentView(R.layout.recents); + mRecentsView = (RecentsView) findViewById(R.id.recents_view); mRecentsView.setCallbacks(this); - mRecentsView.setLayoutParams(new FrameLayout.LayoutParams( - FrameLayout.LayoutParams.MATCH_PARENT, - FrameLayout.LayoutParams.MATCH_PARENT)); mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); - - // Create the empty view - LayoutInflater inflater = LayoutInflater.from(this); - mEmptyView = inflater.inflate(R.layout.recents_empty, mContainerView, false); - mNavBarScrimView = inflater.inflate(R.layout.recents_nav_bar_scrim, mContainerView, false); - mNavBarScrimView.setLayoutParams(new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM)); - - mContainerView = new FrameLayout(this); - mContainerView.addView(mRecentsView); - mContainerView.addView(mEmptyView); - mContainerView.addView(mNavBarScrimView); - setContentView(mContainerView); + mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub); + mFullscreenOverlayStub = (ViewStub) findViewById(R.id.fullscreen_overlay_stub); + mScrimViews = new SystemBarScrimViews(this, mConfig); // Update the recent tasks updateRecentsTasks(getIntent()); + // Prepare the screenshot transition if necessary + if (Constants.DebugFlags.App.EnableScreenshotAppTransition) { + mFullScreenOverlayView = (FullscreenTransitionOverlayView) mFullscreenOverlayStub.inflate(); + mFullScreenOverlayView.setCallbacks(this); + mFullScreenOverlayView.prepareAnimateOnEnterRecents(AlternateRecentsComponent.getLastScreenshot()); + } + // Bind the search app widget when we first start up bindSearchBarAppWidget(); // Add the search bar layout @@ -306,10 +349,10 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView onConfigurationChange(); } - // XXX: Update the shadows + // Private API calls to make the shadows look better try { - sPropertyMethod.invoke(null, "ambientShadowStrength", String.valueOf(35f)); - sPropertyMethod.invoke(null, "ambientRatio", String.valueOf(0.5f)); + Utilities.setShadowProperty("ambientShadowStrength", String.valueOf(35f)); + Utilities.setShadowProperty("ambientRatio", String.valueOf(0.5f)); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { @@ -319,7 +362,9 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView void onConfigurationChange() { // Try and start the enter animation (or restart it on configuration changed) - mRecentsView.startOnEnterAnimation(); + mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(mFullScreenOverlayView)); + // Call our callback + onEnterAnimationTriggered(); } @Override @@ -338,11 +383,16 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // Initialize the loader and the configuration RecentsTaskLoader.initialize(this); - RecentsConfiguration.reinitialize(this); + mConfig = RecentsConfiguration.reinitialize(this); // Update the recent tasks updateRecentsTasks(intent); + // Prepare the screenshot transition if necessary + if (Constants.DebugFlags.App.EnableScreenshotAppTransition) { + mFullScreenOverlayView.prepareAnimateOnEnterRecents(AlternateRecentsComponent.getLastScreenshot()); + } + // Don't attempt to rebind the search bar widget, but just add the search bar layout addSearchBarAppWidgetView(); } @@ -355,12 +405,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } super.onStart(); - // Start listening for widget package changes if there is one bound - RecentsConfiguration config = RecentsConfiguration.getInstance(); - if (config.searchBarAppWidgetId >= 0) { - mAppWidgetHost.startListening(); - } - mVisible = true; } @@ -396,6 +440,11 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // Register any broadcast receivers for the task loader RecentsTaskLoader.getInstance().registerReceivers(this, mRecentsView); + + // Start listening for widget package changes if there is one bound + if (mConfig.searchBarAppWidgetId >= 0) { + mAppWidgetHost.startListening(this); + } } @Override @@ -411,6 +460,11 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView unregisterReceiver(mServiceBroadcastReceiver); unregisterReceiver(mScreenOffReceiver); RecentsTaskLoader.getInstance().unregisterReceivers(); + + // Stop listening for widget package changes if there was one bound + if (mConfig.searchBarAppWidgetId >= 0) { + mAppWidgetHost.stopListening(); + } } @Override @@ -430,12 +484,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } super.onStop(); - // Stop listening for widget package changes if there was one bound - RecentsConfiguration config = RecentsConfiguration.getInstance(); - if (config.searchBarAppWidgetId >= 0) { - mAppWidgetHost.stopListening(); - } - mVisible = false; mTaskLaunched = false; } @@ -470,58 +518,78 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } @Override + public void onUserInteraction() { + mRecentsView.onUserInteraction(); + } + + @Override public void onBackPressed() { - // Unfilter any stacks - if (!mRecentsView.unfilterFilteredStacks()) { - if (!mRecentsView.launchFirstTask()) { - super.onBackPressed(); + // If we are mid-animation into Recents, then reverse it and finish + if (mFullScreenOverlayView == null || + !mFullScreenOverlayView.cancelAnimateOnEnterRecents(mFinishRunnable)) { + // If we are currently filtering in any stacks, unfilter them first + if (!mRecentsView.unfilterFilteredStacks()) { + if (mConfig.launchedFromHome) { + // Just start the animation out of recents + ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this, + null, mFinishLaunchHomeRunnable, null); + mRecentsView.startExitToHomeAnimation( + new ViewAnimation.TaskViewExitContext(exitTrigger)); + } else { + // Otherwise, try and launch the first task + if (!mRecentsView.launchFirstTask()) { + // If there are no tasks, then just finish recents + mFinishLaunchHomeRunnable.run(); + } + } } } } - @Override public void onEnterAnimationTriggered() { - // Fade in the scrim - RecentsConfiguration config = RecentsConfiguration.getInstance(); - if (config.hasNavBarScrim()) { - mNavBarScrimView.setVisibility(View.VISIBLE); - mNavBarScrimView.setAlpha(0f); - mNavBarScrimView.animate().alpha(1f) - .setStartDelay(config.taskBarEnterAnimDelay) - .setDuration(config.navBarScrimEnterDuration) - .setInterpolator(config.fastOutSlowInInterpolator) - .withLayer() - .start(); + // Animate the scrims in + mScrimViews.startEnterRecentsAnimation(); + } + + /**** FullscreenTransitionOverlayView.FullScreenTransitionViewCallbacks Implementation ****/ + + @Override + public void onEnterAnimationComplete(boolean canceled) { + if (!canceled) { + // Reset the full screenshot transition view + if (Constants.DebugFlags.App.EnableScreenshotAppTransition) { + mFullScreenOverlayView.reset(); + } + + // XXX: We should clean up the screenshot in this case as well, but it needs to happen + // after to animate up } + // Recycle the full screen screenshot + AlternateRecentsComponent.consumeLastScreenshot(); } + /**** RecentsView.RecentsViewCallbacks Implementation ****/ + @Override - public void onTaskLaunching(boolean isTaskInStackBounds) { + public void onExitToHomeAnimationTriggered() { + // Animate the scrims out + mScrimViews.startExitRecentsAnimation(); + } + + @Override + public void onTaskLaunching() { mTaskLaunched = true; - // Fade out the scrim - RecentsConfiguration config = RecentsConfiguration.getInstance(); - if (!isTaskInStackBounds && config.hasNavBarScrim()) { - mNavBarScrimView.animate().alpha(0f) - .setStartDelay(0) - .setDuration(config.taskBarExitAnimDuration) - .setInterpolator(config.fastOutSlowInInterpolator) - .withLayer() - .start(); - } + // Mark recents as no longer visible + AlternateRecentsComponent.notifyVisibilityChanged(false); } + /**** RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks Implementation ****/ + @Override - public void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo) { - RecentsConfiguration config = RecentsConfiguration.getInstance(); - SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy(); - if (appWidgetId > -1 && appWidgetId == config.searchBarAppWidgetId) { - // The search provider may have changed, so just delete the old widget and bind it again - ssp.unbindSearchAppWidget(mAppWidgetHost, appWidgetId); - config.updateSearchBarAppWidgetId(this, -1); - // Load the widget again - bindSearchBarAppWidget(); - addSearchBarAppWidgetView(); - } + public void refreshSearchWidget() { + // Load the Search widget again + bindSearchBarAppWidget(); + addSearchBarAppWidgetView(); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java new file mode 100644 index 0000000..d55eba7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java @@ -0,0 +1,67 @@ +/* + * 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.recents; + +import android.appwidget.AppWidgetHost; +import android.appwidget.AppWidgetProviderInfo; +import android.content.Context; + +/** Our special app widget host for the Search widget */ +public class RecentsAppWidgetHost extends AppWidgetHost { + + /* Callbacks to notify when an app package changes */ + interface RecentsAppWidgetHostCallbacks { + public void refreshSearchWidget(); + } + + Context mContext; + RecentsAppWidgetHostCallbacks mCb; + RecentsConfiguration mConfig; + + public RecentsAppWidgetHost(Context context, int hostId) { + super(context, hostId); + mContext = context; + mConfig = RecentsConfiguration.getInstance(); + } + + public void startListening(RecentsAppWidgetHostCallbacks cb) { + mCb = cb; + super.startListening(); + } + + @Override + public void stopListening() { + super.stopListening(); + // Ensure that we release any references to the callbacks + mCb = null; + mContext = null; + } + + @Override + protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo) { + if (mCb == null) return; + + SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy(); + if (appWidgetId > -1 && appWidgetId == mConfig.searchBarAppWidgetId) { + // The search provider may have changed, so just delete the old widget and bind it again + ssp.unbindSearchAppWidget(this, appWidgetId); + // Update the search widget + mConfig.updateSearchBarAppWidgetId(mContext, -1); + mCb.refreshSearchWidget(); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index 0cf6ee6..10978ca 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -37,27 +37,40 @@ public class RecentsConfiguration { DisplayMetrics mDisplayMetrics; - public Rect systemInsets = new Rect(); - public Rect displayRect = new Rect(); - - boolean isLandscape; - boolean transposeRecentsLayoutWithOrientation; - int searchBarAppWidgetId = -1; - + /** Animations */ public float animationPxMovementPerSecond; + /** Interpolators */ public Interpolator fastOutSlowInInterpolator; public Interpolator fastOutLinearInInterpolator; public Interpolator linearOutSlowInInterpolator; + public Interpolator quintOutInterpolator; - public int filteringCurrentViewsMinAnimDuration; - public int filteringNewViewsMinAnimDuration; + /** Filtering */ + public int filteringCurrentViewsAnimDuration; + public int filteringNewViewsAnimDuration; - public int taskStackScrollDismissInfoPaneDistance; + /** Insets */ + public Rect systemInsets = new Rect(); + public Rect displayRect = new Rect(); + + /** Layout */ + boolean isLandscape; + boolean transposeRecentsLayoutWithOrientation; + + /** Search bar */ + int searchBarAppWidgetId = -1; + public int searchBarSpaceHeightPx; + + /** Task stack */ public int taskStackMaxDim; - public float taskStackWidthPaddingPct; public int taskStackTopPaddingPx; + public float taskStackWidthPaddingPct; + /** Task view animation and styles */ + public int taskViewEnterFromHomeDuration; + public int taskViewEnterFromHomeDelay; + public int taskViewExitToHomeDuration; public int taskViewRemoveAnimDuration; public int taskViewRemoveAnimTranslationXPx; public int taskViewTranslationZMinPx; @@ -66,32 +79,56 @@ public class RecentsConfiguration { public int taskViewRoundedCornerRadiusPx; public int taskViewHighlightPx; - public int searchBarSpaceHeightPx; - + /** Task bar colors */ public int taskBarViewDefaultBackgroundColor; - public int taskBarViewDefaultTextColor; public int taskBarViewLightTextColor; public int taskBarViewDarkTextColor; public int taskBarViewHighlightColor; + /** Task bar animations */ public int taskBarEnterAnimDuration; public int taskBarEnterAnimDelay; public int taskBarExitAnimDuration; + public int taskBarDismissDozeDelaySeconds; + /** Nav bar scrim */ public int navBarScrimEnterDuration; - public boolean launchedFromAltTab; - public boolean launchedWithThumbnailAnimation; + /** Launch states */ + public boolean launchedWithAltTab; + public boolean launchedWithNoRecentTasks; + public boolean launchedFromAppWithThumbnail; + public boolean launchedFromAppWithScreenshot; + public boolean launchedFromHome; + /** Dev options */ public boolean developerOptionsEnabled; /** Private constructor */ - private RecentsConfiguration() {} + private RecentsConfiguration(Context context) { + // Properties that don't have to be reloaded with each configuration change can be loaded + // here. + + // Interpolators + fastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.fast_out_slow_in); + fastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.fast_out_linear_in); + linearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.linear_out_slow_in); + quintOutInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.decelerate_quint); + + // Check if the developer options are enabled + ContentResolver cr = context.getContentResolver(); + developerOptionsEnabled = Settings.Global.getInt(cr, + Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0; + } /** Updates the configuration to the current context */ public static RecentsConfiguration reinitialize(Context context) { if (sInstance == null) { - sInstance = new RecentsConfiguration(); + sInstance = new RecentsConfiguration(context); } sInstance.update(context); return sInstance; @@ -108,33 +145,46 @@ public class RecentsConfiguration { DisplayMetrics dm = res.getDisplayMetrics(); mDisplayMetrics = dm; + // Animations + animationPxMovementPerSecond = + res.getDimensionPixelSize(R.dimen.recents_animation_movement_in_dps_per_second); + + // Filtering + filteringCurrentViewsAnimDuration = + res.getInteger(R.integer.recents_filter_animate_current_views_duration); + filteringNewViewsAnimDuration = + res.getInteger(R.integer.recents_filter_animate_new_views_duration); + + // Insets + displayRect.set(0, 0, dm.widthPixels, dm.heightPixels); + + // Layout isLandscape = res.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; transposeRecentsLayoutWithOrientation = res.getBoolean(R.bool.recents_transpose_layout_with_orientation); - if (Console.Enabled) { - Console.log(Constants.Log.UI.MeasureAndLayout, - "[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait", - Console.AnsiGreen); - } - displayRect.set(0, 0, dm.widthPixels, dm.heightPixels); - animationPxMovementPerSecond = - res.getDimensionPixelSize(R.dimen.recents_animation_movement_in_dps_per_second); - filteringCurrentViewsMinAnimDuration = - res.getInteger(R.integer.recents_filter_animate_current_views_min_duration); - filteringNewViewsMinAnimDuration = - res.getInteger(R.integer.recents_filter_animate_new_views_min_duration); + // Search bar + searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height); - taskStackScrollDismissInfoPaneDistance = res.getDimensionPixelSize( - R.dimen.recents_task_stack_scroll_dismiss_info_pane_distance); - taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim); + // Update the search widget id + SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0); + searchBarAppWidgetId = settings.getInt(Constants.Values.App.Key_SearchAppWidgetId, -1); + // Task stack TypedValue widthPaddingPctValue = new TypedValue(); res.getValue(R.dimen.recents_stack_width_padding_percentage, widthPaddingPctValue, true); taskStackWidthPaddingPct = widthPaddingPctValue.getFloat(); + taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim); taskStackTopPaddingPx = res.getDimensionPixelSize(R.dimen.recents_stack_top_padding); + // Task view animation and styles + taskViewEnterFromHomeDuration = + res.getInteger(R.integer.recents_animate_task_enter_from_home_duration); + taskViewEnterFromHomeDelay = + res.getInteger(R.integer.recents_animate_task_enter_from_home_delay); + taskViewExitToHomeDuration = + res.getInteger(R.integer.recents_animate_task_exit_to_home_duration); taskViewRemoveAnimDuration = res.getInteger(R.integer.recents_animate_task_view_remove_duration); taskViewRemoveAnimTranslationXPx = @@ -148,12 +198,9 @@ public class RecentsConfiguration { taskViewShadowOutlineBottomInsetPx = res.getDimensionPixelSize(R.dimen.recents_task_view_shadow_outline_bottom_inset); - searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height); - + // Task bar colors taskBarViewDefaultBackgroundColor = res.getColor(R.color.recents_task_bar_default_background_color); - taskBarViewDefaultTextColor = - res.getColor(R.color.recents_task_bar_default_text_color); taskBarViewLightTextColor = res.getColor(R.color.recents_task_bar_light_text_color); taskBarViewDarkTextColor = @@ -161,31 +208,25 @@ public class RecentsConfiguration { taskBarViewHighlightColor = res.getColor(R.color.recents_task_bar_highlight_color); + // Task bar animations taskBarEnterAnimDuration = res.getInteger(R.integer.recents_animate_task_bar_enter_duration); taskBarEnterAnimDelay = res.getInteger(R.integer.recents_animate_task_bar_enter_delay); taskBarExitAnimDuration = res.getInteger(R.integer.recents_animate_task_bar_exit_duration); + taskBarDismissDozeDelaySeconds = + res.getInteger(R.integer.recents_task_bar_dismiss_delay_seconds); + // Nav bar scrim navBarScrimEnterDuration = res.getInteger(R.integer.recents_nav_bar_scrim_enter_duration); - fastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, - com.android.internal.R.interpolator.fast_out_slow_in); - fastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context, - com.android.internal.R.interpolator.fast_out_linear_in); - linearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, - com.android.internal.R.interpolator.linear_out_slow_in); - - // Check if the developer options are enabled - ContentResolver cr = context.getContentResolver(); - developerOptionsEnabled = Settings.Global.getInt(cr, - Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0; - - // Update the search widget id - SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0); - searchBarAppWidgetId = settings.getInt(Constants.Values.App.Key_SearchAppWidgetId, -1); + if (Console.Enabled) { + Console.log(Constants.Log.UI.MeasureAndLayout, + "[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait", + Console.AnsiGreen); + } } /** Updates the system insets */ @@ -204,8 +245,11 @@ public class RecentsConfiguration { /** Called when the configuration has changed, and we want to reset any configuration specific * members. */ public void updateOnConfigurationChange() { - launchedFromAltTab = false; - launchedWithThumbnailAnimation = false; + launchedWithAltTab = false; + launchedWithNoRecentTasks = false; + launchedFromAppWithThumbnail = false; + launchedFromAppWithScreenshot = false; + launchedFromHome = false; } /** Returns whether the search bar app widget exists. */ @@ -213,9 +257,26 @@ public class RecentsConfiguration { return searchBarAppWidgetId >= 0; } + /** Returns whether the status bar scrim should be animated when shown for the first time. */ + public boolean shouldAnimateStatusBarScrim() { + return launchedFromHome; + } + + /** Returns whether the status bar scrim should be visible. */ + public boolean hasStatusBarScrim() { + return !launchedWithNoRecentTasks; + } + + /** Returns whether the nav bar scrim should be animated when shown for the first time. */ + public boolean shouldAnimateNavBarScrim() { + return true; + } + /** Returns whether the nav bar scrim should be visible. */ public boolean hasNavBarScrim() { - return !transposeRecentsLayoutWithOrientation || !isLandscape; + // Only show the scrim if we have recent tasks, and if the nav bar is not transposed + return !launchedWithNoRecentTasks && + (!transposeRecentsLayoutWithOrientation || !isLandscape); } /** @@ -257,15 +318,4 @@ public class RecentsConfiguration { searchBarSpaceBounds.set(0, 0, width, searchBarSpaceHeightPx); } } - - /** Converts from DPs to PXs */ - public int pxFromDp(float size) { - return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, - size, mDisplayMetrics)); - } - /** Converts from SPs to PXs */ - public int pxFromSp(float size) { - return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, - size, mDisplayMetrics)); - } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsPackageMonitor.java index 8bcc7f5..04d1f1f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsPackageMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsPackageMonitor.java @@ -37,29 +37,29 @@ public class RecentsPackageMonitor extends PackageMonitor { PackageCallbacks mCb; List<ActivityManager.RecentTaskInfo> mTasks; - SystemServicesProxy mSsp; - boolean mRegistered; - - public RecentsPackageMonitor(Context context) { - mSsp = new SystemServicesProxy(context); - } + SystemServicesProxy mSystemServicesProxy; /** Registers the broadcast receivers with the specified callbacks. */ public void register(Context context, PackageCallbacks cb) { + mSystemServicesProxy = new SystemServicesProxy(context); mCb = cb; - if (!mRegistered) { + try { register(context, Looper.getMainLooper(), false); - mRegistered = true; + } catch (IllegalStateException e) { + e.printStackTrace(); } } /** Unregisters the broadcast receivers. */ @Override public void unregister() { - if (mRegistered) { + try { super.unregister(); - mRegistered = false; + } catch (IllegalStateException e) { + e.printStackTrace(); } + mSystemServicesProxy = null; + mCb = null; mTasks.clear(); } @@ -106,7 +106,7 @@ public class RecentsPackageMonitor extends PackageMonitor { // If we know that the component still exists in the package, then skip continue; } - if (mSsp.getActivityInfo(cn) != null) { + if (mSystemServicesProxy.getActivityInfo(cn) != null) { componentsKnownToExist.add(cn); } else { componentsToRemove.add(cn); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java index 113efe3..e554af7 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java @@ -134,10 +134,12 @@ class SystemUIMessageHandler extends Handler { context.sendBroadcast(intent); // Time this path - Console.logTraceTime(Constants.Log.App.TimeRecentsStartup, - Constants.Log.App.TimeRecentsStartupKey, "receivedToggleRecents"); - Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask, - Constants.Log.App.TimeRecentsLaunchKey, "receivedToggleRecents"); + if (Console.Enabled) { + Console.logTraceTime(Constants.Log.App.TimeRecentsStartup, + Constants.Log.App.TimeRecentsStartupKey, "receivedToggleRecents"); + Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask, + Constants.Log.App.TimeRecentsLaunchKey, "receivedToggleRecents"); + } } else if (msg.what == AlternateRecentsComponent.MSG_START_ENTER_ANIMATION) { // Send a broadcast to start the enter animation Intent intent = new Intent(RecentsService.ACTION_START_ENTER_ANIMATION); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java index 4685186..07a6a56 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java @@ -118,6 +118,7 @@ class TaskResourceLoader implements Runnable { TaskResourceLoadQueue mLoadQueue; DrawableLruCache mApplicationIconCache; BitmapLruCache mThumbnailCache; + Bitmap mDefaultThumbnail; boolean mCancelled; boolean mWaitingOnLoadQueue; @@ -125,10 +126,12 @@ class TaskResourceLoader implements Runnable { /** Constructor, creates a new loading thread that loads task resources in the background */ public TaskResourceLoader(TaskResourceLoadQueue loadQueue, DrawableLruCache applicationIconCache, - BitmapLruCache thumbnailCache) { + BitmapLruCache thumbnailCache, + Bitmap defaultThumbnail) { mLoadQueue = loadQueue; mApplicationIconCache = applicationIconCache; mThumbnailCache = thumbnailCache; + mDefaultThumbnail = defaultThumbnail; mMainThreadHandler = new Handler(); mLoadThread = new HandlerThread("Recents-TaskResourceLoader"); mLoadThread.setPriority(Thread.NORM_PRIORITY - 1); @@ -238,6 +241,7 @@ class TaskResourceLoader implements Runnable { loadThumbnail = thumbnail; mThumbnailCache.put(t.key, thumbnail); } else { + loadThumbnail = mDefaultThumbnail; Console.logError(mContext, "Failed to load task top thumbnail for: " + t.key.baseIntent.getComponent().getPackageName()); @@ -330,6 +334,7 @@ public class RecentsTaskLoader { BitmapDrawable mDefaultApplicationIcon; Bitmap mDefaultThumbnail; + Bitmap mLoadingThumbnail; /** Private Constructor */ private RecentsTaskLoader(Context context) { @@ -352,22 +357,26 @@ public class RecentsTaskLoader { // Initialize the proxy, cache and loaders mSystemServicesProxy = new SystemServicesProxy(context); - mPackageMonitor = new RecentsPackageMonitor(context); + mPackageMonitor = new RecentsPackageMonitor(); mLoadQueue = new TaskResourceLoadQueue(); mApplicationIconCache = new DrawableLruCache(iconCacheSize); mThumbnailCache = new BitmapLruCache(thumbnailCacheSize); - mLoader = new TaskResourceLoader(mLoadQueue, mApplicationIconCache, mThumbnailCache); + mLoader = new TaskResourceLoader(mLoadQueue, mApplicationIconCache, mThumbnailCache, + mDefaultThumbnail); // Create the default assets Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); icon.eraseColor(0x00000000); mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); - mDefaultThumbnail.eraseColor(0x00000000); + mDefaultThumbnail.eraseColor(0xFFffffff); + mLoadingThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); + mLoadingThumbnail.eraseColor(0x00000000); mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon); if (Console.Enabled) { Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|defaultBitmaps]", - "icon: " + mDefaultApplicationIcon + " thumbnail: " + mDefaultThumbnail, Console.AnsiRed); + "icon: " + mDefaultApplicationIcon + + " default thumbnail: " + mDefaultThumbnail, Console.AnsiRed); } } @@ -394,7 +403,7 @@ public class RecentsTaskLoader { SystemServicesProxy ssp = mSystemServicesProxy; List<ActivityManager.RecentTaskInfo> tasks = - ssp.getRecentTasks(25, UserHandle.CURRENT.getIdentifier()); + ssp.getRecentTasks(50, UserHandle.CURRENT.getIdentifier()); Collections.reverse(tasks); if (Console.Enabled) { Console.log(Constants.Log.App.TimeSystemCalls, @@ -478,7 +487,7 @@ public class RecentsTaskLoader { // Load the thumbnail (if possible and not the foremost task, from the cache) if (!isForemostTask) { task.thumbnail = mThumbnailCache.get(task.key); - if (task.thumbnail != null) { + if (task.thumbnail != null && !tasksToForceLoad.contains(task)) { // Even though we get things from the cache, we should update them if // they've changed in the bg tasksToForceLoad.add(task); @@ -489,6 +498,7 @@ public class RecentsTaskLoader { Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|loadingTaskThumbnail]"); } + task.thumbnail = ssp.getTaskThumbnail(task.key.id); if (task.thumbnail != null) { task.thumbnail.setHasAlpha(false); @@ -512,20 +522,6 @@ public class RecentsTaskLoader { "" + (System.currentTimeMillis() - t1) + "ms"); } - /* - // Get all the stacks - t1 = System.currentTimeMillis(); - List<ActivityManager.StackInfo> stackInfos = ams.getAllStackInfos(); - Console.log(Constants.Log.App.TimeSystemCalls, "[RecentsTaskLoader|getAllStackInfos]", "" + (System.currentTimeMillis() - t1) + "ms"); - Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|stacks]", "" + tasks.size()); - for (ActivityManager.StackInfo s : stackInfos) { - Console.log(Constants.Log.App.TaskDataLoader, " [RecentsTaskLoader|stack]", s.toString()); - if (stacks.containsKey(s.stackId)) { - stacks.get(s.stackId).setRect(s.bounds); - } - } - */ - // Start the task loader mLoader.start(context); @@ -557,7 +553,7 @@ public class RecentsTaskLoader { requiresLoad = true; } if (thumbnail == null) { - thumbnail = mDefaultThumbnail; + thumbnail = mLoadingThumbnail; requiresLoad = true; } if (requiresLoad) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/ReferenceCountedTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/ReferenceCountedTrigger.java new file mode 100644 index 0000000..d525546 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/ReferenceCountedTrigger.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.recents; + +import android.content.Context; + +import java.util.ArrayList; + +/** + * A ref counted trigger that does some logic when the count is first incremented, or last + * decremented. Not thread safe as it's not currently needed. + */ +public class ReferenceCountedTrigger { + + Context mContext; + int mCount; + ArrayList<Runnable> mFirstIncRunnables = new ArrayList<Runnable>(); + ArrayList<Runnable> mLastDecRunnables = new ArrayList<Runnable>(); + Runnable mErrorRunnable; + + // Convenience runnables + Runnable mIncrementRunnable = new Runnable() { + @Override + public void run() { + increment(); + } + }; + Runnable mDecrementRunnable = new Runnable() { + @Override + public void run() { + decrement(); + } + }; + + public ReferenceCountedTrigger(Context context, Runnable firstIncRunnable, + Runnable lastDecRunnable, Runnable errorRunanable) { + mContext = context; + if (firstIncRunnable != null) mFirstIncRunnables.add(firstIncRunnable); + if (lastDecRunnable != null) mLastDecRunnables.add(lastDecRunnable); + mErrorRunnable = errorRunanable; + } + + /** Increments the ref count */ + public void increment() { + if (mCount == 0 && !mFirstIncRunnables.isEmpty()) { + int numRunnables = mFirstIncRunnables.size(); + for (int i = 0; i < numRunnables; i++) { + mFirstIncRunnables.get(i).run(); + } + } + mCount++; + } + + /** Convenience method to increment this trigger as a runnable */ + public Runnable incrementAsRunnable() { + return mIncrementRunnable; + } + + /** Adds a runnable to the last-decrement runnables list. */ + public void addLastDecrementRunnable(Runnable r) { + mLastDecRunnables.add(r); + } + + /** Decrements the ref count */ + public void decrement() { + mCount--; + if (mCount == 0 && !mLastDecRunnables.isEmpty()) { + int numRunnables = mLastDecRunnables.size(); + for (int i = 0; i < numRunnables; i++) { + mLastDecRunnables.get(i).run(); + } + } else if (mCount < 0) { + if (mErrorRunnable != null) { + mErrorRunnable.run(); + } else { + new Throwable("Invalid ref count").printStackTrace(); + Console.logError(mContext, "Invalid ref count"); + } + } + } + + /** Convenience method to decrement this trigger as a runnable */ + public Runnable decrementAsRunnable() { + return mDecrementRunnable; + } + + /** Returns the current ref count */ + public int getCount() { + return mCount; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java index 7a3ffb8..c47f7d7 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java @@ -30,13 +30,23 @@ import android.content.pm.ActivityInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.util.Log; import android.util.Pair; +import android.view.Display; +import android.view.DisplayInfo; +import android.view.SurfaceControl; +import android.view.WindowManager; import java.util.ArrayList; import java.util.Iterator; @@ -48,16 +58,22 @@ import java.util.Random; * a point of injection when testing UI. */ public class SystemServicesProxy { + final static String TAG = "SystemServicesProxy"; + ActivityManager mAm; AppWidgetManager mAwm; PackageManager mPm; IPackageManager mIpm; UserManager mUm; SearchManager mSm; + WindowManager mWm; + Display mDisplay; String mRecentsPackage; ComponentName mAssistComponent; Bitmap mDummyIcon; + Paint mBgProtectionPaint; + Canvas mBgProtectionCanvas; /** Private constructor */ public SystemServicesProxy(Context context) { @@ -67,8 +83,16 @@ public class SystemServicesProxy { mUm = (UserManager) context.getSystemService(Context.USER_SERVICE); mIpm = AppGlobals.getPackageManager(); mSm = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE); + mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + mDisplay = mWm.getDefaultDisplay(); mRecentsPackage = context.getPackageName(); + // Create the protection paints + mBgProtectionPaint = new Paint(); + mBgProtectionPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP)); + mBgProtectionPaint.setColor(0xFFffffff); + mBgProtectionCanvas = new Canvas(); + // Resolve the assist intent Intent assist = mSm.getAssistIntent(context, false); if (assist != null) { @@ -184,7 +208,20 @@ public class SystemServicesProxy { return thumbnail; } - return mAm.getTaskTopThumbnail(taskId); + Bitmap thumbnail = mAm.getTaskTopThumbnail(taskId); + if (thumbnail != null) { + // We use a dumb heuristic for now, if the thumbnail is purely transparent in the top + // left pixel, then assume the whole thumbnail is transparent. Generally, proper + // screenshots are always composed onto a bitmap that has no alpha. + if (Color.alpha(thumbnail.getPixel(0, 0)) == 0) { + mBgProtectionCanvas.setBitmap(thumbnail); + mBgProtectionCanvas.drawRect(0, 0, thumbnail.getWidth(), thumbnail.getHeight(), + mBgProtectionPaint); + mBgProtectionCanvas.setBitmap(null); + Log.e(TAG, "Invalid screenshot detected from getTaskThumbnail()"); + } + } + return thumbnail; } /** Moves a task to the front with the specified activity options */ @@ -325,4 +362,13 @@ public class SystemServicesProxy { // Delete the app widget host.deleteAppWidgetId(appWidgetId); } + + /** + * Takes a screenshot of the current surface. + */ + public Bitmap takeScreenshot() { + DisplayInfo di = new DisplayInfo(); + mDisplay.getDisplayInfo(di); + return SurfaceControl.screenshot(di.getNaturalWidth(), di.getNaturalHeight()); + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java index 46e6ee9..25875bc 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java @@ -20,8 +20,26 @@ import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + /* Common code */ public class Utilities { + + // Reflection methods for altering shadows + private static Method sPropertyMethod; + static { + try { + Class<?> c = Class.forName("android.view.GLES20Canvas"); + sPropertyMethod = c.getDeclaredMethod("setProperty", String.class, String.class); + if (!sPropertyMethod.isAccessible()) sPropertyMethod.setAccessible(true); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + } + /** * Calculates a consistent animation duration (ms) for all animations depending on the movement * of the object being animated. @@ -66,4 +84,10 @@ public class Utilities { int greyscale = colorToGreyscale(color); return (greyscale < 128) ? lightRes : darkRes; } + + /** Sets some private shadow properties. */ + public static void setShadowProperty(String property, String value) + throws IllegalAccessException, InvocationTargetException { + sPropertyMethod.invoke(null, property, value); + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java b/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java index 1dd1be6..20be415 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java @@ -56,6 +56,13 @@ public class SpaceNode { return mStack; } + /** Returns whether there are any tasks in any stacks below this node. */ + public boolean hasTasks() { + return (mStack.getTaskCount() > 0) || + (mStartNode != null && mStartNode.hasTasks()) || + (mEndNode != null && mEndNode.hasTasks()); + } + /** Returns whether this is a leaf node */ boolean isLeafNode() { return (mStartNode == null) && (mEndNode == null); diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java index 47a506c..f366ef0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java @@ -16,6 +16,7 @@ package com.android.systemui.recents.model; +import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FullscreenTransitionOverlayView.java b/packages/SystemUI/src/com/android/systemui/recents/views/FullscreenTransitionOverlayView.java new file mode 100644 index 0000000..2c632cf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/views/FullscreenTransitionOverlayView.java @@ -0,0 +1,257 @@ +/* + * 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.recents.views; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import com.android.systemui.R; +import com.android.systemui.recents.Console; +import com.android.systemui.recents.Constants; +import com.android.systemui.recents.RecentsConfiguration; + + +/** + * The full screen transition view that gets animated down from the full screen into a task + * thumbnail view. + */ +public class FullscreenTransitionOverlayView extends FrameLayout { + + /** The FullscreenTransitionOverlayView callbacks */ + public interface FullScreenTransitionViewCallbacks { + void onEnterAnimationComplete(boolean canceled); + } + + RecentsConfiguration mConfig; + + FullScreenTransitionViewCallbacks mCb; + + ImageView mScreenshotView; + Rect mClipRect = new Rect(); + Paint mLayerPaint = new Paint(); + + boolean mIsAnimating; + AnimatorSet mEnterAnimation; + + public FullscreenTransitionOverlayView(Context context) { + super(context); + } + + public FullscreenTransitionOverlayView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public FullscreenTransitionOverlayView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public FullscreenTransitionOverlayView(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + mConfig = RecentsConfiguration.getInstance(); + setClipTop(getClipTop()); + setClipBottom(getClipBottom()); + setWillNotDraw(false); + } + + @Override + protected void onFinishInflate() { + mScreenshotView = (ImageView) findViewById(R.id.image); + } + + /** Sets the callbacks */ + public void setCallbacks(FullScreenTransitionViewCallbacks cb) { + mCb = cb; + } + + /** Sets the top clip */ + public void setClipTop(int clip) { + mClipRect.top = clip; + postInvalidateOnAnimation(); + } + + /** Gets the top clip */ + public int getClipTop() { + return mClipRect.top; + } + + /** Sets the bottom clip */ + public void setClipBottom(int clip) { + mClipRect.bottom = clip; + postInvalidateOnAnimation(); + } + + /** Gets the top clip */ + public int getClipBottom() { + return mClipRect.bottom; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + mClipRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); + } + + @Override + public void draw(Canvas canvas) { + int restoreCount = canvas.save(Canvas.CLIP_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); + canvas.clipRect(mClipRect); + super.draw(canvas); + canvas.restoreToCount(restoreCount); + } + + @Override + public boolean hasOverlappingRendering() { + return false; + } + + /** Prepares the screenshot view for the transition into Recents */ + public void prepareAnimateOnEnterRecents(Bitmap screenshot) { + if (!mConfig.launchedFromAppWithScreenshot) return; + + if (Console.Enabled) { + Console.logStartTracingTime(Constants.Log.App.TimeRecentsScreenshotTransition, + Constants.Log.App.TimeRecentsScreenshotTransitionKey); + } + + setClipTop(0); + setClipBottom(getMeasuredHeight()); + setTranslationY(0f); + setScaleX(1f); + setScaleY(1f); + setVisibility(mConfig.launchedFromAppWithScreenshot ? View.VISIBLE : View.INVISIBLE); + if (screenshot != null) { + mScreenshotView.setImageBitmap(screenshot); + } else { + mScreenshotView.setImageDrawable(null); + } + } + + /** Resets the transition view */ + public void reset() { + setVisibility(View.INVISIBLE); + mScreenshotView.setImageDrawable(null); + } + + /** Animates this view as it enters recents */ + public void animateOnEnterRecents(ViewAnimation.TaskViewEnterContext ctx, + final Runnable postAnimRunnable) { + if (Console.Enabled) { + Console.logTraceTime(Constants.Log.App.TimeRecentsScreenshotTransition, + Constants.Log.App.TimeRecentsScreenshotTransitionKey, "Starting"); + } + + // Cancel the current animation + if (mEnterAnimation != null) { + mEnterAnimation.removeAllListeners(); + mEnterAnimation.cancel(); + } + + // Calculate the bottom clip + float scale = (float) ctx.taskRect.width() / getMeasuredWidth(); + int translationY = -mConfig.systemInsets.top + ctx.stackRectSansPeek.top + + ctx.transform.translationY; + int clipBottom = mConfig.systemInsets.top + (int) (ctx.taskRect.height() / scale); + + // Enable the HW Layers on the screenshot view + mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, mLayerPaint); + + // Compose the animation + mEnterAnimation = new AnimatorSet(); + mEnterAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + // Notify any callbacks + mCb.onEnterAnimationComplete(false); + // Run the given post-anim runnable + postAnimRunnable.run(); + // Mark that we are no longer animating + mIsAnimating = false; + // Disable the HW Layers on this view + setLayerType(View.LAYER_TYPE_NONE, mLayerPaint); + + if (Console.Enabled) { + Console.logTraceTime(Constants.Log.App.TimeRecentsScreenshotTransition, + Constants.Log.App.TimeRecentsScreenshotTransitionKey, "Completed"); + } + } + }); + mEnterAnimation.setStartDelay(0); + mEnterAnimation.setDuration(475); + mEnterAnimation.setInterpolator(mConfig.fastOutSlowInInterpolator); + mEnterAnimation.playTogether( + ObjectAnimator.ofInt(this, "clipTop", mConfig.systemInsets.top), + ObjectAnimator.ofInt(this, "clipBottom", clipBottom), + ObjectAnimator.ofFloat(this, "translationY", translationY), + ObjectAnimator.ofFloat(this, "scaleX", scale), + ObjectAnimator.ofFloat(this, "scaleY", scale) + ); + mEnterAnimation.start(); + + mIsAnimating = true; + } + + /** Animates this view back out of Recents if we were in the process of animating in. */ + public boolean cancelAnimateOnEnterRecents(final Runnable postAnimRunnable) { + if (mIsAnimating) { + // Cancel the current animation + if (mEnterAnimation != null) { + mEnterAnimation.removeAllListeners(); + mEnterAnimation.cancel(); + } + + // Compose the animation + mEnterAnimation = new AnimatorSet(); + mEnterAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + // Notify any callbacks + mCb.onEnterAnimationComplete(true); + // Run the given post-anim runnable + postAnimRunnable.run(); + // Mark that we are no longer animating + mIsAnimating = false; + // Disable the HW Layers on the screenshot view + mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, mLayerPaint); + } + }); + mEnterAnimation.setDuration(475); + mEnterAnimation.setInterpolator(mConfig.fastOutSlowInInterpolator); + mEnterAnimation.playTogether( + ObjectAnimator.ofInt(this, "clipTop", 0), + ObjectAnimator.ofInt(this, "clipBottom", getMeasuredHeight()), + ObjectAnimator.ofFloat(this, "translationY", 0f), + ObjectAnimator.ofFloat(this, "scaleX", 1f), + ObjectAnimator.ofFloat(this, "scaleY", 1f) + ); + mEnterAnimation.start(); + + return true; + } + return false; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index db398b1..8afc5b9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -28,6 +28,7 @@ import android.graphics.Rect; import android.net.Uri; import android.os.UserHandle; import android.provider.Settings; +import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.WindowInsets; @@ -44,7 +45,6 @@ import com.android.systemui.recents.model.TaskStack; import java.util.ArrayList; import java.util.Set; - /** * This view is the the top level layout that contains TaskStacks (which are laid out according * to their SpaceNode bounds. @@ -54,10 +54,13 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV /** The RecentsView callbacks */ public interface RecentsViewCallbacks { - public void onTaskLaunching(boolean isTaskInStackBounds); - public void onEnterAnimationTriggered(); + public void onTaskLaunching(); + public void onExitToHomeAnimationTriggered(); } + RecentsConfiguration mConfig; + LayoutInflater mInflater; + // The space partitioning root of this container SpaceNode mBSP; // Whether there are any tasks @@ -67,12 +70,22 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV // Recents view callbacks RecentsViewCallbacks mCb; - LayoutInflater mInflater; - public RecentsView(Context context) { super(context); + } + + public RecentsView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public RecentsView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public RecentsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + mConfig = RecentsConfiguration.getInstance(); mInflater = LayoutInflater.from(context); - setWillNotDraw(false); } /** Sets the callbacks */ @@ -160,18 +173,40 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV } /** Requests all task stacks to start their enter-recents animation */ - public void startOnEnterAnimation() { - // Notify callbacks that we are starting the enter animation - mCb.onEnterAnimationTriggered(); - + public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) { int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); if (child instanceof TaskStackView) { TaskStackView stackView = (TaskStackView) child; - stackView.startOnEnterAnimation(); + stackView.startEnterRecentsAnimation(ctx); + } + } + } + + /** Requests all task stacks to start their exit-recents animation */ + public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) { + // Handle the case when there are no views by incrementing and decrementing after all + // animations are started. + ctx.postAnimationTrigger.increment(); + + if (Constants.DebugFlags.App.EnableHomeTransition) { + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = getChildAt(i); + if (child instanceof TaskStackView) { + TaskStackView stackView = (TaskStackView) child; + stackView.startExitToHomeAnimation(ctx); + } } } + + // Handle the case when there are no views by incrementing and decrementing after all + // animations are started. + ctx.postAnimationTrigger.decrement(); + + // Notify of the exit animation + mCb.onExitToHomeAnimationTriggered(); } /** Adds the search bar */ @@ -215,10 +250,9 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV } // Get the search bar bounds and measure the search bar layout - RecentsConfiguration config = RecentsConfiguration.getInstance(); if (mSearchBar != null) { Rect searchBarSpaceBounds = new Rect(); - config.getSearchBarBounds(width, height - config.systemInsets.top, searchBarSpaceBounds); + mConfig.getSearchBarBounds(width, height - mConfig.systemInsets.top, searchBarSpaceBounds); mSearchBar.measure( MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), MeasureSpec.EXACTLY)); @@ -229,9 +263,9 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV // In addition, we give it the full height, not including the top inset or search bar space, // since we want the tasks to render under the navigation buttons in portrait. Rect taskStackBounds = new Rect(); - config.getTaskStackBounds(width, height, taskStackBounds); - int childWidth = width - config.systemInsets.right; - int childHeight = taskStackBounds.height() - config.systemInsets.top; + mConfig.getTaskStackBounds(width, height, taskStackBounds); + int childWidth = width - mConfig.systemInsets.right; + int childHeight = taskStackBounds.height() - mConfig.systemInsets.top; // Measure each TaskStackView int childCount = getChildCount(); @@ -259,23 +293,22 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV } // Get the search bar bounds so that we lay it out - RecentsConfiguration config = RecentsConfiguration.getInstance(); if (mSearchBar != null) { Rect searchBarSpaceBounds = new Rect(); - config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(), searchBarSpaceBounds); - mSearchBar.layout(config.systemInsets.left + searchBarSpaceBounds.left, - config.systemInsets.top + searchBarSpaceBounds.top, - config.systemInsets.left + mSearchBar.getMeasuredWidth(), - config.systemInsets.top + mSearchBar.getMeasuredHeight()); + mConfig.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(), searchBarSpaceBounds); + mSearchBar.layout(mConfig.systemInsets.left + searchBarSpaceBounds.left, + mConfig.systemInsets.top + searchBarSpaceBounds.top, + mConfig.systemInsets.left + mSearchBar.getMeasuredWidth(), + mConfig.systemInsets.top + mSearchBar.getMeasuredHeight()); } // We offset the stack view by the left inset (if any), but lay it out under the search bar. // In addition, we offset our stack views by the top inset and search bar height, but not // the bottom insets because we want it to render under the navigation buttons. Rect taskStackBounds = new Rect(); - config.getTaskStackBounds(getMeasuredWidth(), getMeasuredHeight(), taskStackBounds); - left += config.systemInsets.left; - top += config.systemInsets.top + taskStackBounds.top; + mConfig.getTaskStackBounds(getMeasuredWidth(), getMeasuredHeight(), taskStackBounds); + left += mConfig.systemInsets.left; + top += mConfig.systemInsets.top + taskStackBounds.top; // Layout each child // XXX: Based on the space node for that task view @@ -289,6 +322,20 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV } } + /** Notifies each task view of the user interaction. */ + public void onUserInteraction() { + // Get the first stack view + TaskStackView stackView = null; + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = getChildAt(i); + if (child instanceof TaskStackView) { + stackView = (TaskStackView) child; + stackView.onUserInteraction(); + } + } + } + /** Focuses the next task in the first stack view */ public void focusNextTask(boolean forward) { // Get the first stack view @@ -324,8 +371,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV } // Update the configuration with the latest system insets and trigger a relayout - RecentsConfiguration config = RecentsConfiguration.getInstance(); - config.updateSystemInsets(insets.getSystemWindowInsets()); + mConfig.updateSystemInsets(insets.getSystemWindowInsets()); requestLayout(); return insets.consumeSystemWindowInsets(false, false, false, true); @@ -355,56 +401,58 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV final TaskStack stack, final Task task) { // Notify any callbacks of the launching of a new task if (mCb != null) { - boolean isTaskInStackBounds = false; - if (stackView != null && tv != null) { - isTaskInStackBounds = stackView.isTaskInStackBounds(tv); - } - mCb.onTaskLaunching(isTaskInStackBounds); + mCb.onTaskLaunching(); + } + + // Upfront the processing of the thumbnail + TaskViewTransform transform; + View sourceView = tv; + int offsetX = 0; + int offsetY = 0; + int stackScroll = stackView.getStackScroll(); + if (tv == null) { + // If there is no actual task view, then use the stack view as the source view + // and then offset to the expected transform rect, but bound this to just + // outside the display rect (to ensure we don't animate from too far away) + sourceView = stackView; + transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll); + offsetX = transform.rect.left; + offsetY = Math.min(transform.rect.top, mConfig.displayRect.height()); + } else { + transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll); } + // Compute the thumbnail to scale up from + ActivityOptions opts = null; + int thumbnailWidth = transform.rect.width(); + int thumbnailHeight = transform.rect.height(); + if (task.thumbnail != null && thumbnailWidth > 0 && thumbnailHeight > 0 && + task.thumbnail.getWidth() > 0 && task.thumbnail.getHeight() > 0) { + // Resize the thumbnail to the size of the view that we are animating from + Bitmap b = Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, + Bitmap.Config.ARGB_8888); + Canvas c = new Canvas(b); + c.drawBitmap(task.thumbnail, + new Rect(0, 0, task.thumbnail.getWidth(), task.thumbnail.getHeight()), + new Rect(0, 0, thumbnailWidth, thumbnailHeight), null); + c.setBitmap(null); + opts = ActivityOptions.makeThumbnailScaleUpAnimation(sourceView, + b, offsetX, offsetY); + } + + final ActivityOptions launchOpts = opts; final Runnable launchRunnable = new Runnable() { @Override public void run() { - TaskViewTransform transform; - View sourceView = tv; - int offsetX = 0; - int offsetY = 0; - int stackScroll = stackView.getStackScroll(); - if (tv == null) { - // If there is no actual task view, then use the stack view as the source view - // and then offset to the expected transform rect, but bound this to just - // outside the display rect (to ensure we don't animate from too far away) - RecentsConfiguration config = RecentsConfiguration.getInstance(); - sourceView = stackView; - transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll); - offsetX = transform.rect.left; - offsetY = Math.min(transform.rect.top, config.displayRect.height()); - } else { - transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll); - } - - // Compute the thumbnail to scale up from - ActivityOptions opts = null; - int thumbnailWidth = transform.rect.width(); - int thumbnailHeight = transform.rect.height(); - if (task.thumbnail != null && thumbnailWidth > 0 && thumbnailHeight > 0 && - task.thumbnail.getWidth() > 0 && task.thumbnail.getHeight() > 0) { - // Resize the thumbnail to the size of the view that we are animating from - Bitmap b = Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, - Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(b); - c.drawBitmap(task.thumbnail, - new Rect(0, 0, task.thumbnail.getWidth(), task.thumbnail.getHeight()), - new Rect(0, 0, thumbnailWidth, thumbnailHeight), null); - c.setBitmap(null); - opts = ActivityOptions.makeThumbnailScaleUpAnimation(sourceView, - b, offsetX, offsetY); + if (Console.Enabled) { + Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask, + Constants.Log.App.TimeRecentsLaunchKey, "preStartActivity"); } if (task.isActive) { // Bring an active task to the foreground RecentsTaskLoader.getInstance().getSystemServicesProxy() - .moveTaskToFront(task.key.id, opts); + .moveTaskToFront(task.key.id, launchOpts); } else { // Launch the activity anew with the desired animation Intent i = new Intent(task.key.baseIntent); @@ -413,8 +461,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV | Intent.FLAG_ACTIVITY_NEW_TASK); try { UserHandle taskUser = new UserHandle(task.userId); - if (opts != null) { - getContext().startActivityAsUser(i, opts.toBundle(), taskUser); + if (launchOpts != null) { + getContext().startActivityAsUser(i, launchOpts.toBundle(), taskUser); } else { getContext().startActivityAsUser(i, taskUser); } @@ -426,19 +474,23 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV onTaskRemoved(task); } - Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask, - Constants.Log.App.TimeRecentsLaunchKey, "startActivity"); + if (Console.Enabled) { + Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask, + Constants.Log.App.TimeRecentsLaunchKey, "startActivity"); + } } }; - Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask, - Constants.Log.App.TimeRecentsLaunchKey, "onTaskLaunched"); + if (Console.Enabled) { + Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask, + Constants.Log.App.TimeRecentsLaunchKey, "onTaskLaunched"); + } // Launch the app right away if there is no task view, otherwise, animate the icon out first if (tv == null) { post(launchRunnable); } else { - tv.animateOnLeavingRecents(launchRunnable); + stackView.animateOnLaunchingTask(tv, launchRunnable); } } @@ -469,6 +521,34 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV isDocument); } + @Override + public void onTaskStackFilterTriggered() { + // Hide the search bar + if (mSearchBar != null) { + mSearchBar.animate() + .alpha(0f) + .setStartDelay(0) + .setInterpolator(mConfig.fastOutSlowInInterpolator) + .setDuration(mConfig.filteringCurrentViewsAnimDuration) + .withLayer() + .start(); + } + } + + @Override + public void onTaskStackUnfilterTriggered() { + // Show the search bar + if (mSearchBar != null) { + mSearchBar.animate() + .alpha(1f) + .setStartDelay(0) + .setInterpolator(mConfig.fastOutSlowInInterpolator) + .setDuration(mConfig.filteringNewViewsAnimDuration) + .withLayer() + .start(); + } + } + /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/ @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java new file mode 100644 index 0000000..5b17b41 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java @@ -0,0 +1,109 @@ +/* + * 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.recents.views; + +import android.app.Activity; +import android.view.View; +import com.android.systemui.R; +import com.android.systemui.recents.RecentsConfiguration; + +/** Manages the scrims for the various system bars. */ +public class SystemBarScrimViews { + + RecentsConfiguration mConfig; + + View mStatusBarScrimView; + View mNavBarScrimView; + + boolean mHasNavBarScrim; + boolean mShouldAnimateStatusBarScrim; + boolean mHasStatusBarScrim; + boolean mShouldAnimateNavBarScrim; + + public SystemBarScrimViews(Activity activity, RecentsConfiguration config) { + mConfig = config; + mStatusBarScrimView = activity.findViewById(R.id.status_bar_scrim); + mNavBarScrimView = activity.findViewById(R.id.nav_bar_scrim); + } + + /** + * Prepares the scrim views for animating when entering Recents. This will be called before + * the first draw. + */ + public void prepareEnterRecentsAnimation() { + mHasNavBarScrim = mConfig.hasNavBarScrim(); + mShouldAnimateNavBarScrim = mConfig.shouldAnimateNavBarScrim(); + mHasStatusBarScrim = mConfig.hasStatusBarScrim(); + mShouldAnimateStatusBarScrim = mConfig.shouldAnimateStatusBarScrim(); + + mNavBarScrimView.setVisibility(mHasNavBarScrim && !mShouldAnimateNavBarScrim ? + View.VISIBLE : View.INVISIBLE); + mStatusBarScrimView.setVisibility(mHasStatusBarScrim && !mShouldAnimateStatusBarScrim ? + View.VISIBLE : View.INVISIBLE); + } + + /** + * Starts animating the scrim views when entering Recents. + */ + public void startEnterRecentsAnimation() { + if (mHasStatusBarScrim && mShouldAnimateStatusBarScrim) { + mStatusBarScrimView.setTranslationY(-mStatusBarScrimView.getMeasuredHeight()); + mStatusBarScrimView.animate() + .translationY(0) + .setStartDelay(mConfig.taskBarEnterAnimDelay) + .setDuration(mConfig.navBarScrimEnterDuration) + .setInterpolator(mConfig.quintOutInterpolator) + .withStartAction(new Runnable() { + @Override + public void run() { + mStatusBarScrimView.setVisibility(View.VISIBLE); + } + }) + .start(); + } + if (mHasNavBarScrim && mShouldAnimateNavBarScrim) { + mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight()); + mNavBarScrimView.animate() + .translationY(0) + .setStartDelay(mConfig.taskBarEnterAnimDelay) + .setDuration(mConfig.navBarScrimEnterDuration) + .setInterpolator(mConfig.quintOutInterpolator) + .withStartAction(new Runnable() { + @Override + public void run() { + mNavBarScrimView.setVisibility(View.VISIBLE); + } + }) + .start(); + } + } + + /** + * Starts animating the scrim views when leaving Recents (either via launching a task, or + * going home). + */ + public void startExitRecentsAnimation() { + if (mHasNavBarScrim && mShouldAnimateNavBarScrim) { + mNavBarScrimView.animate() + .translationY(mNavBarScrimView.getMeasuredHeight()) + .setStartDelay(0) + .setDuration(mConfig.taskBarExitAnimDuration) + .setInterpolator(mConfig.fastOutSlowInInterpolator) + .start(); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java index c10ddd1..80f804d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java @@ -23,7 +23,11 @@ import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.drawable.Drawable; +import android.graphics.drawable.RippleDrawable; import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewPropertyAnimator; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; @@ -36,6 +40,9 @@ import com.android.systemui.recents.model.Task; /* The task bar view */ class TaskBarView extends FrameLayout { + + RecentsConfiguration mConfig; + Task mTask; ImageView mDismissButton; @@ -45,6 +52,7 @@ class TaskBarView extends FrameLayout { Drawable mLightDismissDrawable; Drawable mDarkDismissDrawable; + Paint mLayerPaint = new Paint(); static Paint sHighlightPaint; public TaskBarView(Context context) { @@ -61,6 +69,7 @@ class TaskBarView extends FrameLayout { public TaskBarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); + mConfig = RecentsConfiguration.getInstance(); setWillNotDraw(false); // Load the dismiss resources @@ -70,59 +79,77 @@ class TaskBarView extends FrameLayout { // Configure the highlight paint if (sHighlightPaint == null) { - RecentsConfiguration config = RecentsConfiguration.getInstance(); sHighlightPaint = new Paint(); sHighlightPaint.setStyle(Paint.Style.STROKE); - sHighlightPaint.setStrokeWidth(config.taskViewHighlightPx); - sHighlightPaint.setColor(config.taskBarViewHighlightColor); + sHighlightPaint.setStrokeWidth(mConfig.taskViewHighlightPx); + sHighlightPaint.setColor(mConfig.taskBarViewHighlightColor); sHighlightPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD)); sHighlightPaint.setAntiAlias(true); } } @Override + public boolean onTouchEvent(MotionEvent event) { + if (Constants.DebugFlags.App.EnableTaskBarTouchEvents) { + return super.onTouchEvent(event); + } + // We ignore taps on the task bar except on the filter and dismiss buttons + return true; + } + + @Override protected void onFinishInflate() { // Initialize the icon and description views mApplicationIcon = (ImageView) findViewById(R.id.application_icon); mActivityDescription = (TextView) findViewById(R.id.activity_description); mDismissButton = (ImageView) findViewById(R.id.dismiss_task); + + // Hide the backgrounds if they are ripple drawables + if (!Constants.DebugFlags.App.EnableTaskFiltering) { + if (mApplicationIcon.getBackground() instanceof RippleDrawable) { + mApplicationIcon.setBackground(null); + } + } } @Override protected void onDraw(Canvas canvas) { - RecentsConfiguration config = RecentsConfiguration.getInstance(); - // Draw the highlight at the top edge (but put the bottom edge just out of view) - float offset = config.taskViewHighlightPx / 2f; - float radius = config.taskViewRoundedCornerRadiusPx; + float offset = mConfig.taskViewHighlightPx / 2f; + float radius = mConfig.taskViewRoundedCornerRadiusPx; canvas.drawRoundRect(-offset, 0f, (float) getMeasuredWidth() + offset, getMeasuredHeight() + radius, radius, radius, sHighlightPaint); } /** Synchronizes this bar view's properties with the task's transform */ - void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform, - TaskViewTransform toTransform, int duration) { - RecentsConfiguration config = RecentsConfiguration.getInstance(); - if (duration > 0) { - if (animateFromTransform != null) { - mDismissButton.setAlpha(animateFromTransform.dismissAlpha); - } - mDismissButton.animate() - .alpha(toTransform.dismissAlpha) + void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int duration) { + if (duration > 0 && (mDismissButton.getVisibility() == View.VISIBLE)) { + ViewPropertyAnimator anim = mDismissButton.animate(); + + // Animate to the final state + if (toTransform.hasDismissAlphaChangedFrom(mDismissButton.getAlpha())) { + anim.alpha(toTransform.dismissAlpha) .setStartDelay(0) .setDuration(duration) - .setInterpolator(config.fastOutSlowInInterpolator) + .setInterpolator(mConfig.fastOutSlowInInterpolator) .withLayer() .start(); + } } else { - mDismissButton.setAlpha(toTransform.dismissAlpha); + // Set the changed properties + if (toTransform.hasDismissAlphaChangedFrom(mDismissButton.getAlpha())) { + mDismissButton.setAlpha(toTransform.dismissAlpha); + } } - mDismissButton.invalidate(); + } + + @Override + public boolean hasOverlappingRendering() { + return false; } /** Binds the bar view to the task */ void rebindToTask(Task t, boolean animate) { - RecentsConfiguration configuration = RecentsConfiguration.getInstance(); mTask = t; // If an activity icon is defined, then we use that as the primary icon to show in the bar, // otherwise, we fall back to the application icon @@ -134,19 +161,14 @@ class TaskBarView extends FrameLayout { mActivityDescription.setText(t.activityLabel); // Try and apply the system ui tint int tint = t.colorPrimary; - if (Constants.DebugFlags.App.EnableTaskBarThemeColors && tint != 0) { - setBackgroundColor(tint); - mActivityDescription.setTextColor(Utilities.getIdealColorForBackgroundColor(tint, - configuration.taskBarViewLightTextColor, configuration.taskBarViewDarkTextColor)); - mDismissButton.setImageDrawable(Utilities.getIdealResourceForBackgroundColor(tint, - mLightDismissDrawable, mDarkDismissDrawable)); - } else { - setBackgroundColor(configuration.taskBarViewDefaultBackgroundColor); - mActivityDescription.setTextColor(configuration.taskBarViewDefaultTextColor); - } - if (animate) { - // XXX: Investigate how expensive it will be to create a second bitmap and crossfade + if (!Constants.DebugFlags.App.EnableTaskBarThemeColors || tint == 0) { + tint = mConfig.taskBarViewDefaultBackgroundColor; } + setBackgroundColor(tint); + mActivityDescription.setTextColor(Utilities.getIdealColorForBackgroundColor(tint, + mConfig.taskBarViewLightTextColor, mConfig.taskBarViewDarkTextColor)); + mDismissButton.setImageDrawable(Utilities.getIdealResourceForBackgroundColor(tint, + mLightDismissDrawable, mDarkDismissDrawable)); } /** Unbinds the bar view from the task */ @@ -155,4 +177,88 @@ class TaskBarView extends FrameLayout { mApplicationIcon.setImageDrawable(null); mActivityDescription.setText(""); } + + /** Prepares this task view for the enter-recents animations. This is called earlier in the + * first layout because the actual animation into recents may take a long time. */ + public void prepareEnterRecentsAnimation() { + setVisibility(View.INVISIBLE); + } + + /** Animates this task bar as it enters recents */ + public void startEnterRecentsAnimation(int delay, Runnable postAnimRunnable) { + // Animate the task bar of the first task view + setVisibility(View.VISIBLE); + setTranslationY(-getMeasuredHeight()); + animate() + .translationY(0) + .setStartDelay(delay) + .setInterpolator(mConfig.fastOutSlowInInterpolator) + .setDuration(mConfig.taskBarEnterAnimDuration) + .withEndAction(postAnimRunnable) + .start(); + } + + /** Animates this task bar as it exits recents */ + public void startLaunchTaskAnimation(Runnable preAnimRunnable, final Runnable postAnimRunnable) { + // Animate the task bar out of the first task view + animate() + .translationY(-getMeasuredHeight()) + .setStartDelay(0) + .setInterpolator(mConfig.fastOutLinearInInterpolator) + .setDuration(mConfig.taskBarExitAnimDuration) + .withStartAction(preAnimRunnable) + .withEndAction(new Runnable() { + @Override + public void run() { + post(postAnimRunnable); + } + }) + .start(); + } + + /** Animates this task bar dismiss button when launching a task. */ + public void startLaunchTaskDismissAnimation() { + if (mDismissButton.getVisibility() == View.VISIBLE) { + mDismissButton.animate().cancel(); + mDismissButton.animate() + .alpha(0f) + .setStartDelay(0) + .setInterpolator(mConfig.fastOutSlowInInterpolator) + .setDuration(mConfig.taskBarExitAnimDuration) + .withLayer() + .start(); + } + } + + /** Animates this task bar if the user does not interact with the stack after a certain time. */ + public void startNoUserInteractionAnimation() { + mDismissButton.setVisibility(View.VISIBLE); + mDismissButton.setAlpha(0f); + mDismissButton.animate() + .alpha(1f) + .setStartDelay(0) + .setInterpolator(mConfig.fastOutLinearInInterpolator) + .setDuration(mConfig.taskBarEnterAnimDuration) + .withLayer() + .start(); + } + + /** Mark this task view that the user does has not interacted with the stack after a certain time. */ + public void setNoUserInteractionState() { + if (mDismissButton.getVisibility() != View.VISIBLE) { + mDismissButton.animate().cancel(); + mDismissButton.setVisibility(View.VISIBLE); + mDismissButton.setAlpha(1f); + } + } + + /** Enable the hw layers on this task view */ + void enableHwLayers() { + mDismissButton.setLayerType(View.LAYER_TYPE_HARDWARE, mLayerPaint); + } + + /** Disable the hw layers on this task view */ + void disableHwLayers() { + mDismissButton.setLayerType(View.LAYER_TYPE_NONE, mLayerPaint); + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 8d9f8be..1cf28b9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -26,21 +26,19 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.Region; -import android.util.Pair; import android.view.LayoutInflater; import android.view.MotionEvent; -import android.view.VelocityTracker; import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewParent; import android.widget.FrameLayout; import android.widget.OverScroller; import com.android.systemui.R; import com.android.systemui.recents.Console; import com.android.systemui.recents.Constants; +import com.android.systemui.recents.DozeTrigger; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.RecentsPackageMonitor; import com.android.systemui.recents.RecentsTaskLoader; +import com.android.systemui.recents.ReferenceCountedTrigger; import com.android.systemui.recents.Utilities; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; @@ -60,12 +58,18 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal public void onTaskLaunched(TaskStackView stackView, TaskView tv, TaskStack stack, Task t); public void onTaskAppInfoLaunched(Task t); public void onTaskRemoved(Task t); + public void onTaskStackFilterTriggered(); + public void onTaskStackUnfilterTriggered(); } + RecentsConfiguration mConfig; + TaskStack mStack; TaskStackViewTouchHandler mTouchHandler; TaskStackViewCallbacks mCb; ViewPool<TaskView, Task> mViewPool; + ArrayList<TaskViewTransform> mTaskTransforms = new ArrayList<TaskViewTransform>(); + DozeTrigger mUIDozeTrigger; // The various rects that define the stack view Rect mRect = new Rect(); @@ -83,24 +87,74 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal ObjectAnimator mScrollAnimator; // Optimizations - int mHwLayersRefCount; + ReferenceCountedTrigger mHwLayersTrigger; int mStackViewsAnimationDuration; boolean mStackViewsDirty = true; boolean mAwaitingFirstLayout = true; boolean mStartEnterAnimationRequestedAfterLayout; + ViewAnimation.TaskViewEnterContext mStartEnterAnimationContext; int[] mTmpVisibleRange = new int[2]; Rect mTmpRect = new Rect(); Rect mTmpRect2 = new Rect(); LayoutInflater mInflater; + Runnable mReturnAllViewsToPoolRunnable = new Runnable() { + @Override + public void run() { + int childCount = getChildCount(); + for (int i = childCount - 1; i >= 0; i--) { + mViewPool.returnViewToPool((TaskView) getChildAt(i)); + } + } + }; + public TaskStackView(Context context, TaskStack stack) { super(context); + mConfig = RecentsConfiguration.getInstance(); mStack = stack; mStack.setCallbacks(this); mScroller = new OverScroller(context); mTouchHandler = new TaskStackViewTouchHandler(context, this); mViewPool = new ViewPool<TaskView, Task>(context, this); mInflater = LayoutInflater.from(context); + mUIDozeTrigger = new DozeTrigger(mConfig.taskBarDismissDozeDelaySeconds, new Runnable() { + @Override + public void run() { + // Show the task bar dismiss buttons + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + TaskView tv = (TaskView) getChildAt(i); + tv.startNoUserInteractionAnimation(); + } + } + }); + mHwLayersTrigger = new ReferenceCountedTrigger(getContext(), new Runnable() { + @Override + public void run() { + // Enable hw layers on each of the children + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + TaskView tv = (TaskView) getChildAt(i); + tv.enableHwLayers(); + } + } + }, new Runnable() { + @Override + public void run() { + // Disable hw layers on each of the children + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + TaskView tv = (TaskView) getChildAt(i); + tv.disableHwLayers(); + } + } + }, new Runnable() { + @Override + public void run() { + new Throwable("Invalid hw layers ref count").printStackTrace(); + Console.logError(getContext(), "Invalid HW layers ref count"); + } + }); } /** Sets the callbacks */ @@ -118,7 +172,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal "[TaskStackView|requestSynchronize]", "" + duration + "ms", Console.AnsiYellow); } if (!mStackViewsDirty) { - invalidate(); + invalidate(mStackRect); } if (mAwaitingFirstLayout) { // Skip the animation if we are awaiting first layout @@ -129,7 +183,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mStackViewsDirty = true; } - // XXX: Optimization: Use a mapping of Task -> View + /** Finds the child view given a specific task */ private TaskView getChildViewForTask(Task t) { int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { @@ -141,12 +195,20 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal return null; } - /** Update/get the transform */ + /** Update/get the transform (creates a new TaskViewTransform) */ public TaskViewTransform getStackTransform(int indexInStack, int stackScroll) { TaskViewTransform transform = new TaskViewTransform(); + return getStackTransform(indexInStack, stackScroll, transform); + } + /** Update/get the transform */ + public TaskViewTransform getStackTransform(int indexInStack, int stackScroll, + TaskViewTransform transformOut) { // Return early if we have an invalid index - if (indexInStack < 0) return transform; + if (indexInStack < 0) { + transformOut.reset(); + return transformOut; + } // Map the items to an continuous position relative to the specified scroll int numPeekCards = Constants.Values.TaskStackView.StackPeekNumCards; @@ -163,54 +225,66 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal float scale = Math.max(minScale, Math.min(1f, minScale + ((boundedT + (numPeekCards + 1)) * scaleInc))); float scaleYOffset = ((1f - scale) * mTaskRect.height()) / 2; - transform.scale = scale; + transformOut.scale = scale; - // Set the translation + // Set the y translation if (boundedT < 0f) { - transform.translationY = (int) ((Math.max(-numPeekCards, boundedT) / + transformOut.translationY = (int) ((Math.max(-numPeekCards, boundedT) / numPeekCards) * peekHeight - scaleYOffset); } else { - transform.translationY = (int) (boundedT * overlapHeight - scaleYOffset); + transformOut.translationY = (int) (boundedT * overlapHeight - scaleYOffset); } // Set the z translation - RecentsConfiguration config = RecentsConfiguration.getInstance(); - int minZ = config.taskViewTranslationZMinPx; - int incZ = config.taskViewTranslationZIncrementPx; - transform.translationZ = (int) Math.max(minZ, minZ + ((boundedT + numPeekCards) * incZ)); + int minZ = mConfig.taskViewTranslationZMinPx; + int incZ = mConfig.taskViewTranslationZIncrementPx; + transformOut.translationZ = (int) Math.max(minZ, minZ + ((boundedT + numPeekCards) * incZ)); // Set the alphas - transform.dismissAlpha = Math.max(-1f, Math.min(0f, t + 1)) + 1f; + transformOut.dismissAlpha = Math.max(-1f, Math.min(0f, t + 1)) + 1f; // Update the rect and visibility - transform.rect.set(mTaskRect); + transformOut.rect.set(mTaskRect); if (t < -(numPeekCards + 1)) { - transform.visible = false; + transformOut.visible = false; } else { - transform.rect.offset(0, transform.translationY); - Utilities.scaleRectAboutCenter(transform.rect, transform.scale); - transform.visible = Rect.intersects(mRect, transform.rect); + transformOut.rect.offset(0, transformOut.translationY); + Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale); + transformOut.visible = Rect.intersects(mRect, transformOut.rect); } - transform.t = t; - return transform; + transformOut.t = t; + return transformOut; } /** * Gets the stack transforms of a list of tasks, and returns the visible range of tasks. */ - private ArrayList<TaskViewTransform> getStackTransforms(ArrayList<Task> tasks, - int stackScroll, - int[] visibleRangeOut, - boolean boundTranslationsToRect) { + private void updateStackTransforms(ArrayList<TaskViewTransform> taskTransforms, + ArrayList<Task> tasks, + int stackScroll, + int[] visibleRangeOut, + boolean boundTranslationsToRect) { // XXX: Optimization: Use binary search to find the visible range - ArrayList<TaskViewTransform> taskTransforms = new ArrayList<TaskViewTransform>(); + int taskTransformCount = taskTransforms.size(); int taskCount = tasks.size(); int firstVisibleIndex = -1; int lastVisibleIndex = -1; + + // We can reuse the task transforms where possible to reduce object allocation + if (taskTransformCount < taskCount) { + // If there are less transforms than tasks, then add as many transforms as necessary + for (int i = taskTransformCount; i < taskCount; i++) { + taskTransforms.add(new TaskViewTransform()); + } + } else if (taskTransformCount > taskCount) { + // If there are more transforms than tasks, then just subset the transform list + taskTransforms.subList(0, taskCount); + } + + // Update the stack transforms for (int i = 0; i < taskCount; i++) { - TaskViewTransform transform = getStackTransform(i, stackScroll); - taskTransforms.add(transform); + TaskViewTransform transform = getStackTransform(i, stackScroll, taskTransforms.get(i)); if (transform.visible) { if (firstVisibleIndex < 0) { firstVisibleIndex = i; @@ -226,6 +300,19 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal visibleRangeOut[0] = firstVisibleIndex; visibleRangeOut[1] = lastVisibleIndex; } + } + + /** + * Gets the stack transforms of a list of tasks, and returns the visible range of tasks. This + * call is less optimal than calling updateStackTransforms directly. + */ + private ArrayList<TaskViewTransform> getStackTransforms(ArrayList<Task> tasks, + int stackScroll, + int[] visibleRangeOut, + boolean boundTranslationsToRect) { + ArrayList<TaskViewTransform> taskTransforms = new ArrayList<TaskViewTransform>(); + updateStackTransforms(taskTransforms, tasks, stackScroll, visibleRangeOut, + boundTranslationsToRect); return taskTransforms; } @@ -245,14 +332,13 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int[] visibleRange = mTmpVisibleRange; int stackScroll = getStackScroll(); ArrayList<Task> tasks = mStack.getTasks(); - ArrayList<TaskViewTransform> taskTransforms = getStackTransforms(tasks, stackScroll, - visibleRange, false); + updateStackTransforms(mTaskTransforms, tasks, stackScroll, visibleRange, false); // Update the visible state of all the tasks int taskCount = tasks.size(); for (int i = 0; i < taskCount; i++) { Task task = tasks.get(i); - TaskViewTransform transform = taskTransforms.get(i); + TaskViewTransform transform = mTaskTransforms.get(i); TaskView tv = getChildViewForTask(task); if (transform.visible) { @@ -263,7 +349,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal if (mStackViewsAnimationDuration > 0 && i != 0) { int fromIndex = (transform.t < 0) ? (visibleRange[0] - 1) : (visibleRange[1] + 1); - tv.updateViewPropertiesToTaskTransform(null, + tv.updateViewPropertiesToTaskTransform( getStackTransform(fromIndex, stackScroll), 0); } } @@ -281,10 +367,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal TaskView tv = (TaskView) getChildAt(i); Task task = tv.getTask(); int taskIndex = mStack.indexOfTask(task); - if (taskIndex < 0 || !taskTransforms.get(taskIndex).visible) { + if (taskIndex < 0 || !mTaskTransforms.get(taskIndex).visible) { mViewPool.returnViewToPool(tv); } else { - tv.updateViewPropertiesToTaskTransform(null, taskTransforms.get(taskIndex), + tv.updateViewPropertiesToTaskTransform(mTaskTransforms.get(taskIndex), mStackViewsAnimationDuration); } } @@ -302,11 +388,13 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal /** Sets the current stack scroll */ public void setStackScroll(int value) { mStackScroll = value; + mUIDozeTrigger.poke(); requestSynchronizeStackViewsWithModel(); } /** Sets the current stack scroll without synchronizing the stack view with the model */ public void setStackScrollRaw(int value) { mStackScroll = value; + mUIDozeTrigger.poke(); } /** Sets the current stack scroll to the initial state when you first enter recents */ public void setStackScrollToInitialState() { @@ -361,7 +449,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll); mScrollAnimator.setDuration(Utilities.calculateTranslationAnimationDuration(newScroll - curScroll, 250)); - mScrollAnimator.setInterpolator(RecentsConfiguration.getInstance().fastOutSlowInInterpolator); + mScrollAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { @@ -473,6 +561,20 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } + /** Animates a task view in this stack as it launches. */ + public void animateOnLaunchingTask(TaskView tv, final Runnable r) { + // Hide each of the task bar dismiss buttons + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + TaskView t = (TaskView) getChildAt(i); + if (t == tv) { + t.startLaunchTaskAnimation(r, true); + } else { + t.startLaunchTaskAnimation(null, false); + } + } + } + /** Focuses the task at the specified index in the stack */ void focusTask(int taskIndex, boolean scrollToNewPosition) { if (Console.Enabled) { @@ -543,48 +645,31 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal /** Enables the hw layers and increments the hw layer requirement ref count */ void addHwLayersRefCount(String reason) { if (Console.Enabled) { + int refCount = mHwLayersTrigger.getCount(); Console.log(Constants.Log.UI.HwLayers, "[TaskStackView|addHwLayersRefCount] refCount: " + - mHwLayersRefCount + "->" + (mHwLayersRefCount + 1) + " " + reason); + refCount + "->" + (refCount + 1) + " " + reason); } - if (mHwLayersRefCount == 0) { - // Enable hw layers on each of the children - int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - TaskView tv = (TaskView) getChildAt(i); - tv.enableHwLayers(); - } - } - mHwLayersRefCount++; + mHwLayersTrigger.increment(); } /** Decrements the hw layer requirement ref count and disables the hw layers when we don't need them anymore. */ void decHwLayersRefCount(String reason) { if (Console.Enabled) { + int refCount = mHwLayersTrigger.getCount(); Console.log(Constants.Log.UI.HwLayers, "[TaskStackView|decHwLayersRefCount] refCount: " + - mHwLayersRefCount + "->" + (mHwLayersRefCount - 1) + " " + reason); - } - mHwLayersRefCount--; - if (mHwLayersRefCount == 0) { - // Disable hw layers on each of the children - int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - TaskView tv = (TaskView) getChildAt(i); - tv.disableHwLayers(); - } - } else if (mHwLayersRefCount < 0) { - new Throwable("Invalid hw layers ref count").printStackTrace(); - Console.logError(getContext(), "Invalid HW layers ref count"); + refCount + "->" + (refCount - 1) + " " + reason); } + mHwLayersTrigger.decrement(); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { setStackScroll(mScroller.getCurrY()); - invalidate(); + invalidate(mStackRect); // If we just finished scrolling, then disable the hw layers if (mScroller.isFinished()) { @@ -616,7 +701,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { if (Constants.DebugFlags.App.EnableTaskStackClipping) { - RecentsConfiguration config = RecentsConfiguration.getInstance(); TaskView tv = (TaskView) child; TaskView nextTv = null; TaskView tmpTv = null; @@ -632,13 +716,13 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } // Clip against the next view (if we aren't animating its alpha) - if (nextTv != null && nextTv.getAlpha() == 1f) { + if (nextTv != null) { Rect curRect = tv.getClippingRect(mTmpRect); Rect nextRect = nextTv.getClippingRect(mTmpRect2); // The hit rects are relative to the task view, which needs to be offset by // the system bar height - curRect.offset(0, config.systemInsets.top); - nextRect.offset(0, config.systemInsets.top); + curRect.offset(0, mConfig.systemInsets.top); + nextRect.offset(0, mConfig.systemInsets.top); // Compute the clip region Region clipRegion = new Region(); clipRegion.op(curRect, Region.Op.UNION); @@ -660,7 +744,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Note: We let the stack view be the full height because we want the cards to go under the // navigation bar if possible. However, the stack rects which we use to calculate // max scroll, etc. need to take the nav bar into account - RecentsConfiguration config = RecentsConfiguration.getInstance(); // Compute the stack rects mRect.set(0, 0, width, height); @@ -668,8 +751,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mStackRect.left += insetLeft; mStackRect.bottom -= insetBottom; - int widthPadding = (int) (config.taskStackWidthPaddingPct * mStackRect.width()); - int heightPadding = config.taskStackTopPaddingPx; + int widthPadding = (int) (mConfig.taskStackWidthPaddingPct * mStackRect.width()); + int heightPadding = mConfig.taskStackTopPaddingPx; if (Constants.DebugFlags.App.EnableSearchLayout) { mStackRect.top += heightPadding; mStackRect.left += widthPadding; @@ -707,10 +790,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } // Compute our stack/task rects - RecentsConfiguration config = RecentsConfiguration.getInstance(); Rect taskStackBounds = new Rect(); - config.getTaskStackBounds(width, height, taskStackBounds); - computeRects(width, height, taskStackBounds.left, config.systemInsets.bottom); + mConfig.getTaskStackBounds(width, height, taskStackBounds); + computeRects(width, height, taskStackBounds.left, mConfig.systemInsets.bottom); // Debug logging if (Constants.Log.UI.MeasureAndLayout) { @@ -768,48 +850,73 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } if (mAwaitingFirstLayout) { - RecentsConfiguration config = RecentsConfiguration.getInstance(); + // Mark that we have completely the first layout + mAwaitingFirstLayout = false; - // Update the focused task index to be the next item to the top task - if (config.launchedFromAltTab) { - focusTask(Math.max(0, mStack.getTaskCount() - 2), false); - } + // Start dozing + mUIDozeTrigger.startDozing(); // Prepare the first view for its enter animation - if (config.launchedWithThumbnailAnimation) { - TaskView tv = (TaskView) getChildAt(getChildCount() - 1); - if (tv != null) { - tv.prepareAnimateOnEnterRecents(); - } + int offsetTopAlign = -mTaskRect.top; + int offscreenY = mRect.bottom - (mTaskRect.top - mRect.top); + for (int i = childCount - 1; i >= 0; i--) { + TaskView tv = (TaskView) getChildAt(i); + tv.prepareEnterRecentsAnimation((i == (getChildCount() - 1)), offsetTopAlign, + offscreenY, mTaskRect); } - // Mark that we have completely the first layout - mAwaitingFirstLayout = false; - // If the enter animation started already and we haven't completed a layout yet, do the // enter animation now if (mStartEnterAnimationRequestedAfterLayout) { - startOnEnterAnimation(); + startEnterRecentsAnimation(mStartEnterAnimationContext); + mStartEnterAnimationRequestedAfterLayout = false; + mStartEnterAnimationContext = null; + } + + // Update the focused task index to be the next item to the top task + if (mConfig.launchedWithAltTab) { + focusTask(Math.max(0, mStack.getTaskCount() - 2), false); } } } /** Requests this task stacks to start it's enter-recents animation */ - public void startOnEnterAnimation() { - RecentsConfiguration config = RecentsConfiguration.getInstance(); - if (!config.launchedWithThumbnailAnimation) return; - + public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) { // If we are still waiting to layout, then just defer until then if (mAwaitingFirstLayout) { mStartEnterAnimationRequestedAfterLayout = true; + mStartEnterAnimationContext = ctx; return; } - // Animate the task bar of the first task view - TaskView tv = (TaskView) getChildAt(getChildCount() - 1); - if (tv != null) { - tv.animateOnEnterRecents(); + // Animate all the task views into view + ctx.taskRect = mTaskRect; + ctx.stackRectSansPeek = mStackRectSansPeek; + int childCount = getChildCount(); + for (int i = childCount - 1; i >= 0; i--) { + TaskView tv = (TaskView) getChildAt(i); + TaskViewTransform transform = getStackTransform(mStack.indexOfTask(tv.getTask()), + getStackScroll()); + ctx.stackViewIndex = i; + ctx.stackViewCount = childCount; + ctx.isFrontMost = (i == (getChildCount() - 1)); + ctx.transform = transform; + tv.startEnterRecentsAnimation(ctx); + } + } + + /** Requests this task stacks to start it's exit-recents animation. */ + public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) { + // Animate all the task views into view + ctx.offscreenTranslationY = mRect.bottom - (mTaskRect.top - mRect.top); + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + TaskView tv = (TaskView) getChildAt(i); + tv.startExitToHomeAnimation(ctx); } + + // Add a runnable to the post animation ref counter to clear all the views + ctx.postAnimationTrigger.addLastDecrementRunnable(mReturnAllViewsToPoolRunnable); } @Override @@ -822,6 +929,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal return isTransformedTouchPointInView(x, y, child, null); } + /** Pokes the dozer on user interaction. */ + void onUserInteraction() { + // Poke the doze trigger if it is dozing + mUIDozeTrigger.poke(); + } + /**** TaskStackCallbacks Implementation ****/ @Override @@ -833,15 +946,14 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal public void onStackTaskRemoved(TaskStack stack, Task t) { // Remove the view associated with this task, we can't rely on updateTransforms // to work here because the task is no longer in the list - int childCount = getChildCount(); - for (int i = childCount - 1; i >= 0; i--) { - TaskView tv = (TaskView) getChildAt(i); - if (tv.getTask() == t) { - mViewPool.returnViewToPool(tv); - break; - } + TaskView tv = getChildViewForTask(t); + if (tv != null) { + mViewPool.returnViewToPool(tv); } + // Notify the callback that we've removed the task and it can clean up after it + mCb.onTaskRemoved(t); + // Update the min/max scroll and animate other task views into their new positions updateMinMaxScroll(true); int movement = (int) (Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height()); @@ -870,11 +982,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int getExitTransformsForFilterAnimation(ArrayList<Task> curTasks, ArrayList<TaskViewTransform> curTaskTransforms, ArrayList<Task> tasks, ArrayList<TaskViewTransform> taskTransforms, - HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransformsOut, - ArrayList<TaskView> childrenToRemoveOut, - RecentsConfiguration config) { + HashMap<TaskView, TaskViewTransform> childViewTransformsOut, + ArrayList<TaskView> childrenToRemoveOut) { // Animate all of the existing views out of view (if they are not in the visible range in // the new stack) or to their final positions in the new stack + int offset = 0; int movement = 0; int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { @@ -899,10 +1011,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal movement = Math.max(movement, Math.abs(toTransform.translationY - (int) tv.getTranslationY())); } - childViewTransformsOut.put(tv, new Pair(0, toTransform)); + + toTransform.startDelay = offset * Constants.Values.TaskStackView.FilterStartDelay; + childViewTransformsOut.put(tv, toTransform); + offset++; } - return Utilities.calculateTranslationAnimationDuration(movement, - config.filteringCurrentViewsMinAnimDuration); + return mConfig.filteringCurrentViewsAnimDuration; } /** @@ -911,8 +1025,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal */ int getEnterTransformsForFilterAnimation(ArrayList<Task> tasks, ArrayList<TaskViewTransform> taskTransforms, - HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransformsOut, - RecentsConfiguration config) { + HashMap<TaskView, TaskViewTransform> childViewTransformsOut) { int offset = 0; int movement = 0; int taskCount = tasks.size(); @@ -928,11 +1041,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Compose a new transform to fade and slide the new task in TaskViewTransform fromTransform = new TaskViewTransform(toTransform); tv.prepareTaskTransformForFilterTaskHidden(fromTransform); - tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0); + tv.updateViewPropertiesToTaskTransform(fromTransform, 0); - int startDelay = offset * - Constants.Values.TaskStackView.FilterStartDelay; - childViewTransformsOut.put(tv, new Pair(startDelay, toTransform)); + toTransform.startDelay = offset * Constants.Values.TaskStackView.FilterStartDelay; + childViewTransformsOut.put(tv, toTransform); // Use the movement of the new views to calculate the duration of the animation movement = Math.max(movement, @@ -941,8 +1053,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } } - return Utilities.calculateTranslationAnimationDuration(movement, - config.filteringNewViewsMinAnimDuration); + return mConfig.filteringNewViewsAnimDuration; } /** Orchestrates the animations of the current child views and any new views. */ @@ -950,31 +1061,28 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal ArrayList<TaskViewTransform> curTaskTransforms, final ArrayList<Task> tasks, final ArrayList<TaskViewTransform> taskTransforms) { - final RecentsConfiguration config = RecentsConfiguration.getInstance(); - // Calculate the transforms to animate out all the existing views if they are not in the // new visible range (or to their final positions in the stack if they are) final ArrayList<TaskView> childrenToRemove = new ArrayList<TaskView>(); - final HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransforms = - new HashMap<TaskView, Pair<Integer, TaskViewTransform>>(); + final HashMap<TaskView, TaskViewTransform> childViewTransforms = + new HashMap<TaskView, TaskViewTransform>(); int duration = getExitTransformsForFilterAnimation(curTasks, curTaskTransforms, tasks, - taskTransforms, childViewTransforms, childrenToRemove, config); + taskTransforms, childViewTransforms, childrenToRemove); // If all the current views are in the visible range of the new stack, then don't wait for // views to animate out and animate all the new views into their place final boolean unifyNewViewAnimation = childrenToRemove.isEmpty(); if (unifyNewViewAnimation) { int inDuration = getEnterTransformsForFilterAnimation(tasks, taskTransforms, - childViewTransforms, config); + childViewTransforms); duration = Math.max(duration, inDuration); } // Animate all the views to their final transforms for (final TaskView tv : childViewTransforms.keySet()) { - Pair<Integer, TaskViewTransform> t = childViewTransforms.get(tv); + TaskViewTransform t = childViewTransforms.get(tv); tv.animate().cancel(); tv.animate() - .setStartDelay(t.first) .withEndAction(new Runnable() { @Override public void run() { @@ -989,17 +1097,16 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // For views that are not already visible, animate them in childViewTransforms.clear(); int duration = getEnterTransformsForFilterAnimation(tasks, - taskTransforms, childViewTransforms, config); + taskTransforms, childViewTransforms); for (final TaskView tv : childViewTransforms.keySet()) { - Pair<Integer, TaskViewTransform> t = childViewTransforms.get(tv); - tv.animate().setStartDelay(t.first); - tv.updateViewPropertiesToTaskTransform(null, t.second, duration); + TaskViewTransform t = childViewTransforms.get(tv); + tv.updateViewPropertiesToTaskTransform(t, duration); } } } } }); - tv.updateViewPropertiesToTaskTransform(null, t.second, duration); + tv.updateViewPropertiesToTaskTransform(t, duration); } } @@ -1026,6 +1133,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Animate doFilteringAnimation(curTasks, curTaskTransforms, tasks, taskTransforms); + + // Notify any callbacks + mCb.onTaskStackFilterTriggered(); } @Override @@ -1049,6 +1159,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Clear the saved vars mStashedScroll = 0; + + // Notify any callbacks + mCb.onTaskStackUnfilterTriggered(); } /**** ViewPoolConsumer Implementation ****/ @@ -1095,7 +1208,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Request that this tasks's data be filled RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); loader.loadTaskData(task); - // Find the index where this task should be placed in the children int insertIndex = -1; int childCount = getChildCount(); @@ -1111,6 +1223,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // but just in case, re-enable it here tv.setClipViewInStack(true); + // If the doze trigger has already fired, then update the state for this task view + if (mUIDozeTrigger.hasTriggered()) { + tv.setNoUserInteractionState(); + } + // Add/attach the view to the hierarchy if (Console.Enabled) { Console.log(Constants.Log.ViewPool.PoolCallbacks, " [TaskStackView|insertIndex]", @@ -1127,7 +1244,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } // Enable hw layers on this view if hw layers are enabled on the stack - if (mHwLayersRefCount > 0) { + if (mHwLayersTrigger.getCount() > 0) { tv.enableHwLayers(); } } @@ -1172,8 +1289,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal Task task = tv.getTask(); // Remove the task from the view mStack.removeTask(task); - // Notify the callback that we've removed the task and it can clean up after it - mCb.onTaskRemoved(task); } /**** View.OnClickListener Implementation ****/ @@ -1187,6 +1302,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal task + " cb: " + mCb); } + // Cancel any doze triggers + mUIDozeTrigger.stopDozing(); + if (mCb != null) { mCb.onTaskLaunched(this, tv, mStack, task); } @@ -1196,7 +1314,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal @Override public void onComponentRemoved(Set<ComponentName> cns) { - RecentsConfiguration config = RecentsConfiguration.getInstance(); // For other tasks, just remove them directly if they no longer exist ArrayList<Task> tasks = mStack.getTasks(); for (int i = tasks.size() - 1; i >= 0; i--) { @@ -1205,7 +1322,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal TaskView tv = getChildViewForTask(t); if (tv != null) { // For visible children, defer removing the task until after the animation - tv.animateRemoval(new Runnable() { + tv.startDeleteTaskAnimation(new Runnable() { @Override public void run() { mStack.removeTask(t); @@ -1218,393 +1335,4 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } } -} - -/* Handles touch events */ -class TaskStackViewTouchHandler implements SwipeHelper.Callback { - static int INACTIVE_POINTER_ID = -1; - - TaskStackView mSv; - VelocityTracker mVelocityTracker; - - boolean mIsScrolling; - - int mInitialMotionX, mInitialMotionY; - int mLastMotionX, mLastMotionY; - int mActivePointerId = INACTIVE_POINTER_ID; - TaskView mActiveTaskView = null; - - int mTotalScrollMotion; - int mMinimumVelocity; - int mMaximumVelocity; - // The scroll touch slop is used to calculate when we start scrolling - int mScrollTouchSlop; - // The page touch slop is used to calculate when we start swiping - float mPagingTouchSlop; - - SwipeHelper mSwipeHelper; - boolean mInterceptedBySwipeHelper; - - public TaskStackViewTouchHandler(Context context, TaskStackView sv) { - ViewConfiguration configuration = ViewConfiguration.get(context); - mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); - mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); - mScrollTouchSlop = configuration.getScaledTouchSlop(); - mPagingTouchSlop = configuration.getScaledPagingTouchSlop(); - mSv = sv; - - - float densityScale = context.getResources().getDisplayMetrics().density; - mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, mPagingTouchSlop); - mSwipeHelper.setMinAlpha(1f); - } - - /** Velocity tracker helpers */ - void initOrResetVelocityTracker() { - if (mVelocityTracker == null) { - mVelocityTracker = VelocityTracker.obtain(); - } else { - mVelocityTracker.clear(); - } - } - void initVelocityTrackerIfNotExists() { - if (mVelocityTracker == null) { - mVelocityTracker = VelocityTracker.obtain(); - } - } - void recycleVelocityTracker() { - if (mVelocityTracker != null) { - mVelocityTracker.recycle(); - mVelocityTracker = null; - } - } - - /** Returns the view at the specified coordinates */ - TaskView findViewAtPoint(int x, int y) { - int childCount = mSv.getChildCount(); - for (int i = childCount - 1; i >= 0; i--) { - TaskView tv = (TaskView) mSv.getChildAt(i); - if (tv.getVisibility() == View.VISIBLE) { - if (mSv.isTransformedTouchPointInView(x, y, tv)) { - return tv; - } - } - } - return null; - } - - /** Touch preprocessing for handling below */ - public boolean onInterceptTouchEvent(MotionEvent ev) { - if (Console.Enabled) { - Console.log(Constants.Log.UI.TouchEvents, - "[TaskStackViewTouchHandler|interceptTouchEvent]", - Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue); - } - - // Return early if we have no children - boolean hasChildren = (mSv.getChildCount() > 0); - if (!hasChildren) { - return false; - } - - // Pass through to swipe helper if we are swiping - mInterceptedBySwipeHelper = mSwipeHelper.onInterceptTouchEvent(ev); - if (mInterceptedBySwipeHelper) { - return true; - } - - boolean wasScrolling = !mSv.mScroller.isFinished() || - (mSv.mScrollAnimator != null && mSv.mScrollAnimator.isRunning()); - int action = ev.getAction(); - switch (action & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: { - // Save the touch down info - mInitialMotionX = mLastMotionX = (int) ev.getX(); - mInitialMotionY = mLastMotionY = (int) ev.getY(); - mActivePointerId = ev.getPointerId(0); - mActiveTaskView = findViewAtPoint(mLastMotionX, mLastMotionY); - // Stop the current scroll if it is still flinging - mSv.abortScroller(); - mSv.abortBoundScrollAnimation(); - // Initialize the velocity tracker - initOrResetVelocityTracker(); - mVelocityTracker.addMovement(ev); - // Check if the scroller is finished yet - mIsScrolling = !mSv.mScroller.isFinished(); - break; - } - case MotionEvent.ACTION_MOVE: { - if (mActivePointerId == INACTIVE_POINTER_ID) break; - - int activePointerIndex = ev.findPointerIndex(mActivePointerId); - int y = (int) ev.getY(activePointerIndex); - int x = (int) ev.getX(activePointerIndex); - if (Math.abs(y - mInitialMotionY) > mScrollTouchSlop) { - // Save the touch move info - mIsScrolling = true; - // Initialize the velocity tracker if necessary - initVelocityTrackerIfNotExists(); - mVelocityTracker.addMovement(ev); - // Disallow parents from intercepting touch events - final ViewParent parent = mSv.getParent(); - if (parent != null) { - parent.requestDisallowInterceptTouchEvent(true); - } - // Enable HW layers - mSv.addHwLayersRefCount("stackScroll"); - } - - mLastMotionX = x; - mLastMotionY = y; - break; - } - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: { - // Animate the scroll back if we've cancelled - mSv.animateBoundScroll(); - // Disable HW layers - if (mIsScrolling) { - mSv.decHwLayersRefCount("stackScroll"); - } - // Reset the drag state and the velocity tracker - mIsScrolling = false; - mActivePointerId = INACTIVE_POINTER_ID; - mActiveTaskView = null; - mTotalScrollMotion = 0; - recycleVelocityTracker(); - break; - } - } - - return wasScrolling || mIsScrolling; - } - - /** Handles touch events once we have intercepted them */ - public boolean onTouchEvent(MotionEvent ev) { - if (Console.Enabled) { - Console.log(Constants.Log.UI.TouchEvents, - "[TaskStackViewTouchHandler|touchEvent]", - Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue); - } - - // Short circuit if we have no children - boolean hasChildren = (mSv.getChildCount() > 0); - if (!hasChildren) { - return false; - } - - // Pass through to swipe helper if we are swiping - if (mInterceptedBySwipeHelper && mSwipeHelper.onTouchEvent(ev)) { - return true; - } - - // Update the velocity tracker - initVelocityTrackerIfNotExists(); - mVelocityTracker.addMovement(ev); - - int action = ev.getAction(); - switch (action & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: { - // Save the touch down info - mInitialMotionX = mLastMotionX = (int) ev.getX(); - mInitialMotionY = mLastMotionY = (int) ev.getY(); - mActivePointerId = ev.getPointerId(0); - mActiveTaskView = findViewAtPoint(mLastMotionX, mLastMotionY); - // Stop the current scroll if it is still flinging - mSv.abortScroller(); - mSv.abortBoundScrollAnimation(); - // Initialize the velocity tracker - initOrResetVelocityTracker(); - mVelocityTracker.addMovement(ev); - // Disallow parents from intercepting touch events - final ViewParent parent = mSv.getParent(); - if (parent != null) { - parent.requestDisallowInterceptTouchEvent(true); - } - break; - } - case MotionEvent.ACTION_POINTER_DOWN: { - final int index = ev.getActionIndex(); - mActivePointerId = ev.getPointerId(index); - mLastMotionX = (int) ev.getX(index); - mLastMotionY = (int) ev.getY(index); - break; - } - case MotionEvent.ACTION_MOVE: { - if (mActivePointerId == INACTIVE_POINTER_ID) break; - - int activePointerIndex = ev.findPointerIndex(mActivePointerId); - int x = (int) ev.getX(activePointerIndex); - int y = (int) ev.getY(activePointerIndex); - int yTotal = Math.abs(y - mInitialMotionY); - int deltaY = mLastMotionY - y; - if (!mIsScrolling) { - if (yTotal > mScrollTouchSlop) { - mIsScrolling = true; - // Initialize the velocity tracker - initOrResetVelocityTracker(); - mVelocityTracker.addMovement(ev); - // Disallow parents from intercepting touch events - final ViewParent parent = mSv.getParent(); - if (parent != null) { - parent.requestDisallowInterceptTouchEvent(true); - } - // Enable HW layers - mSv.addHwLayersRefCount("stackScroll"); - } - } - if (mIsScrolling) { - int curStackScroll = mSv.getStackScroll(); - int overScrollAmount = mSv.getScrollAmountOutOfBounds(curStackScroll + deltaY); - if (overScrollAmount != 0) { - // Bound the overscroll to a fixed amount, and inversely scale the y-movement - // relative to how close we are to the max overscroll - float maxOverScroll = mSv.mTaskRect.height() / 3f; - deltaY = Math.round(deltaY * (1f - (Math.min(maxOverScroll, overScrollAmount) - / maxOverScroll))); - } - mSv.setStackScroll(curStackScroll + deltaY); - if (mSv.isScrollOutOfBounds()) { - mVelocityTracker.clear(); - } - } - mLastMotionX = x; - mLastMotionY = y; - mTotalScrollMotion += Math.abs(deltaY); - break; - } - case MotionEvent.ACTION_UP: { - final VelocityTracker velocityTracker = mVelocityTracker; - velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); - int velocity = (int) velocityTracker.getYVelocity(mActivePointerId); - - if (mIsScrolling && (Math.abs(velocity) > mMinimumVelocity)) { - // Enable HW layers on the stack - mSv.addHwLayersRefCount("flingScroll"); - // XXX: Make this animation a function of the velocity AND distance - int overscrollRange = (int) (Math.min(1f, - Math.abs((float) velocity / mMaximumVelocity)) * - Constants.Values.TaskStackView.TaskStackOverscrollRange); - - if (Console.Enabled) { - Console.log(Constants.Log.UI.TouchEvents, - "[TaskStackViewTouchHandler|fling]", - "scroll: " + mSv.getStackScroll() + " velocity: " + velocity + - " maxVelocity: " + mMaximumVelocity + - " overscrollRange: " + overscrollRange, - Console.AnsiGreen); - } - - // Fling scroll - mSv.mScroller.fling(0, mSv.getStackScroll(), - 0, -velocity, - 0, 0, - mSv.mMinScroll, mSv.mMaxScroll, - 0, overscrollRange); - // Invalidate to kick off computeScroll - mSv.invalidate(); - } else if (mSv.isScrollOutOfBounds()) { - // Animate the scroll back into bounds - // XXX: Make this animation a function of the velocity OR distance - mSv.animateBoundScroll(); - } - - if (mIsScrolling) { - // Disable HW layers - mSv.decHwLayersRefCount("stackScroll"); - } - mActivePointerId = INACTIVE_POINTER_ID; - mIsScrolling = false; - mTotalScrollMotion = 0; - recycleVelocityTracker(); - break; - } - case MotionEvent.ACTION_POINTER_UP: { - int pointerIndex = ev.getActionIndex(); - int pointerId = ev.getPointerId(pointerIndex); - if (pointerId == mActivePointerId) { - // Select a new active pointer id and reset the motion state - final int newPointerIndex = (pointerIndex == 0) ? 1 : 0; - mActivePointerId = ev.getPointerId(newPointerIndex); - mLastMotionX = (int) ev.getX(newPointerIndex); - mLastMotionY = (int) ev.getY(newPointerIndex); - mVelocityTracker.clear(); - } - break; - } - case MotionEvent.ACTION_CANCEL: { - if (mIsScrolling) { - // Disable HW layers - mSv.decHwLayersRefCount("stackScroll"); - } - if (mSv.isScrollOutOfBounds()) { - // Animate the scroll back into bounds - // XXX: Make this animation a function of the velocity OR distance - mSv.animateBoundScroll(); - } - mActivePointerId = INACTIVE_POINTER_ID; - mIsScrolling = false; - mTotalScrollMotion = 0; - recycleVelocityTracker(); - break; - } - } - return true; - } - - /**** SwipeHelper Implementation ****/ - - @Override - public View getChildAtPosition(MotionEvent ev) { - return findViewAtPoint((int) ev.getX(), (int) ev.getY()); - } - - @Override - public boolean canChildBeDismissed(View v) { - return true; - } - - @Override - public void onBeginDrag(View v) { - // Enable HW layers - mSv.addHwLayersRefCount("swipeBegin"); - // Disable clipping with the stack while we are swiping - TaskView tv = (TaskView) v; - tv.setClipViewInStack(false); - // Disallow parents from intercepting touch events - final ViewParent parent = mSv.getParent(); - if (parent != null) { - parent.requestDisallowInterceptTouchEvent(true); - } - } - - @Override - public void onSwipeChanged(View v, float delta) { - // Do nothing - } - - @Override - public void onChildDismissed(View v) { - TaskView tv = (TaskView) v; - mSv.onTaskDismissed(tv); - - // Re-enable clipping with the stack (we will reuse this view) - tv.setClipViewInStack(true); - - // Disable HW layers - mSv.decHwLayersRefCount("swipeComplete"); - } - - @Override - public void onSnapBackCompleted(View v) { - // Re-enable clipping with the stack - TaskView tv = (TaskView) v; - tv.setClipViewInStack(true); - } - - @Override - public void onDragCancelled(View v) { - // Disable HW layers - mSv.decHwLayersRefCount("swipeCancelled"); - } -} +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java new file mode 100644 index 0000000..d2f18ae --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java @@ -0,0 +1,415 @@ +/* + * 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.recents.views; + +import android.content.Context; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewParent; +import com.android.systemui.recents.Console; +import com.android.systemui.recents.Constants; + +/* Handles touch events for a TaskStackView. */ +class TaskStackViewTouchHandler implements SwipeHelper.Callback { + static int INACTIVE_POINTER_ID = -1; + + TaskStackView mSv; + VelocityTracker mVelocityTracker; + + boolean mIsScrolling; + + int mInitialMotionX, mInitialMotionY; + int mLastMotionX, mLastMotionY; + int mActivePointerId = INACTIVE_POINTER_ID; + TaskView mActiveTaskView = null; + + int mTotalScrollMotion; + int mMinimumVelocity; + int mMaximumVelocity; + // The scroll touch slop is used to calculate when we start scrolling + int mScrollTouchSlop; + // The page touch slop is used to calculate when we start swiping + float mPagingTouchSlop; + + SwipeHelper mSwipeHelper; + boolean mInterceptedBySwipeHelper; + + public TaskStackViewTouchHandler(Context context, TaskStackView sv) { + ViewConfiguration configuration = ViewConfiguration.get(context); + mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); + mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); + mScrollTouchSlop = configuration.getScaledTouchSlop(); + mPagingTouchSlop = configuration.getScaledPagingTouchSlop(); + mSv = sv; + + + float densityScale = context.getResources().getDisplayMetrics().density; + mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, mPagingTouchSlop); + mSwipeHelper.setMinAlpha(1f); + } + + /** Velocity tracker helpers */ + void initOrResetVelocityTracker() { + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } else { + mVelocityTracker.clear(); + } + } + void initVelocityTrackerIfNotExists() { + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + } + void recycleVelocityTracker() { + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + } + + /** Returns the view at the specified coordinates */ + TaskView findViewAtPoint(int x, int y) { + int childCount = mSv.getChildCount(); + for (int i = childCount - 1; i >= 0; i--) { + TaskView tv = (TaskView) mSv.getChildAt(i); + if (tv.getVisibility() == View.VISIBLE) { + if (mSv.isTransformedTouchPointInView(x, y, tv)) { + return tv; + } + } + } + return null; + } + + /** Touch preprocessing for handling below */ + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (Console.Enabled) { + Console.log(Constants.Log.UI.TouchEvents, + "[TaskStackViewTouchHandler|interceptTouchEvent]", + Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue); + } + + // Return early if we have no children + boolean hasChildren = (mSv.getChildCount() > 0); + if (!hasChildren) { + return false; + } + + // Pass through to swipe helper if we are swiping + mInterceptedBySwipeHelper = mSwipeHelper.onInterceptTouchEvent(ev); + if (mInterceptedBySwipeHelper) { + return true; + } + + boolean wasScrolling = !mSv.mScroller.isFinished() || + (mSv.mScrollAnimator != null && mSv.mScrollAnimator.isRunning()); + int action = ev.getAction(); + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_DOWN: { + // Save the touch down info + mInitialMotionX = mLastMotionX = (int) ev.getX(); + mInitialMotionY = mLastMotionY = (int) ev.getY(); + mActivePointerId = ev.getPointerId(0); + mActiveTaskView = findViewAtPoint(mLastMotionX, mLastMotionY); + // Stop the current scroll if it is still flinging + mSv.abortScroller(); + mSv.abortBoundScrollAnimation(); + // Initialize the velocity tracker + initOrResetVelocityTracker(); + mVelocityTracker.addMovement(ev); + // Check if the scroller is finished yet + mIsScrolling = !mSv.mScroller.isFinished(); + break; + } + case MotionEvent.ACTION_MOVE: { + if (mActivePointerId == INACTIVE_POINTER_ID) break; + + int activePointerIndex = ev.findPointerIndex(mActivePointerId); + int y = (int) ev.getY(activePointerIndex); + int x = (int) ev.getX(activePointerIndex); + if (Math.abs(y - mInitialMotionY) > mScrollTouchSlop) { + // Save the touch move info + mIsScrolling = true; + // Initialize the velocity tracker if necessary + initVelocityTrackerIfNotExists(); + mVelocityTracker.addMovement(ev); + // Disallow parents from intercepting touch events + final ViewParent parent = mSv.getParent(); + if (parent != null) { + parent.requestDisallowInterceptTouchEvent(true); + } + // Enable HW layers + mSv.addHwLayersRefCount("stackScroll"); + } + + mLastMotionX = x; + mLastMotionY = y; + break; + } + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: { + // Animate the scroll back if we've cancelled + mSv.animateBoundScroll(); + // Disable HW layers + if (mIsScrolling) { + mSv.decHwLayersRefCount("stackScroll"); + } + // Reset the drag state and the velocity tracker + mIsScrolling = false; + mActivePointerId = INACTIVE_POINTER_ID; + mActiveTaskView = null; + mTotalScrollMotion = 0; + recycleVelocityTracker(); + break; + } + } + + return wasScrolling || mIsScrolling; + } + + /** Handles touch events once we have intercepted them */ + public boolean onTouchEvent(MotionEvent ev) { + if (Console.Enabled) { + Console.log(Constants.Log.UI.TouchEvents, + "[TaskStackViewTouchHandler|touchEvent]", + Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue); + } + + // Short circuit if we have no children + boolean hasChildren = (mSv.getChildCount() > 0); + if (!hasChildren) { + return false; + } + + // Pass through to swipe helper if we are swiping + if (mInterceptedBySwipeHelper && mSwipeHelper.onTouchEvent(ev)) { + return true; + } + + // Update the velocity tracker + initVelocityTrackerIfNotExists(); + mVelocityTracker.addMovement(ev); + + int action = ev.getAction(); + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_DOWN: { + // Save the touch down info + mInitialMotionX = mLastMotionX = (int) ev.getX(); + mInitialMotionY = mLastMotionY = (int) ev.getY(); + mActivePointerId = ev.getPointerId(0); + mActiveTaskView = findViewAtPoint(mLastMotionX, mLastMotionY); + // Stop the current scroll if it is still flinging + mSv.abortScroller(); + mSv.abortBoundScrollAnimation(); + // Initialize the velocity tracker + initOrResetVelocityTracker(); + mVelocityTracker.addMovement(ev); + // Disallow parents from intercepting touch events + final ViewParent parent = mSv.getParent(); + if (parent != null) { + parent.requestDisallowInterceptTouchEvent(true); + } + break; + } + case MotionEvent.ACTION_POINTER_DOWN: { + final int index = ev.getActionIndex(); + mActivePointerId = ev.getPointerId(index); + mLastMotionX = (int) ev.getX(index); + mLastMotionY = (int) ev.getY(index); + break; + } + case MotionEvent.ACTION_MOVE: { + if (mActivePointerId == INACTIVE_POINTER_ID) break; + + int activePointerIndex = ev.findPointerIndex(mActivePointerId); + int x = (int) ev.getX(activePointerIndex); + int y = (int) ev.getY(activePointerIndex); + int yTotal = Math.abs(y - mInitialMotionY); + int deltaY = mLastMotionY - y; + if (!mIsScrolling) { + if (yTotal > mScrollTouchSlop) { + mIsScrolling = true; + // Initialize the velocity tracker + initOrResetVelocityTracker(); + mVelocityTracker.addMovement(ev); + // Disallow parents from intercepting touch events + final ViewParent parent = mSv.getParent(); + if (parent != null) { + parent.requestDisallowInterceptTouchEvent(true); + } + // Enable HW layers + mSv.addHwLayersRefCount("stackScroll"); + } + } + if (mIsScrolling) { + int curStackScroll = mSv.getStackScroll(); + int overScrollAmount = mSv.getScrollAmountOutOfBounds(curStackScroll + deltaY); + if (overScrollAmount != 0) { + // Bound the overscroll to a fixed amount, and inversely scale the y-movement + // relative to how close we are to the max overscroll + float maxOverScroll = mSv.mTaskRect.height() / 3f; + deltaY = Math.round(deltaY * (1f - (Math.min(maxOverScroll, overScrollAmount) + / maxOverScroll))); + } + mSv.setStackScroll(curStackScroll + deltaY); + if (mSv.isScrollOutOfBounds()) { + mVelocityTracker.clear(); + } + } + mLastMotionX = x; + mLastMotionY = y; + mTotalScrollMotion += Math.abs(deltaY); + break; + } + case MotionEvent.ACTION_UP: { + final VelocityTracker velocityTracker = mVelocityTracker; + velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); + int velocity = (int) velocityTracker.getYVelocity(mActivePointerId); + + if (mIsScrolling && (Math.abs(velocity) > mMinimumVelocity)) { + // Enable HW layers on the stack + mSv.addHwLayersRefCount("flingScroll"); + // XXX: Make this animation a function of the velocity AND distance + int overscrollRange = (int) (Math.min(1f, + Math.abs((float) velocity / mMaximumVelocity)) * + Constants.Values.TaskStackView.TaskStackOverscrollRange); + + if (Console.Enabled) { + Console.log(Constants.Log.UI.TouchEvents, + "[TaskStackViewTouchHandler|fling]", + "scroll: " + mSv.getStackScroll() + " velocity: " + velocity + + " maxVelocity: " + mMaximumVelocity + + " overscrollRange: " + overscrollRange, + Console.AnsiGreen); + } + + // Fling scroll + mSv.mScroller.fling(0, mSv.getStackScroll(), + 0, -velocity, + 0, 0, + mSv.mMinScroll, mSv.mMaxScroll, + 0, overscrollRange); + // Invalidate to kick off computeScroll + mSv.invalidate(mSv.mStackRect); + } else if (mSv.isScrollOutOfBounds()) { + // Animate the scroll back into bounds + // XXX: Make this animation a function of the velocity OR distance + mSv.animateBoundScroll(); + } + + if (mIsScrolling) { + // Disable HW layers + mSv.decHwLayersRefCount("stackScroll"); + } + mActivePointerId = INACTIVE_POINTER_ID; + mIsScrolling = false; + mTotalScrollMotion = 0; + recycleVelocityTracker(); + break; + } + case MotionEvent.ACTION_POINTER_UP: { + int pointerIndex = ev.getActionIndex(); + int pointerId = ev.getPointerId(pointerIndex); + if (pointerId == mActivePointerId) { + // Select a new active pointer id and reset the motion state + final int newPointerIndex = (pointerIndex == 0) ? 1 : 0; + mActivePointerId = ev.getPointerId(newPointerIndex); + mLastMotionX = (int) ev.getX(newPointerIndex); + mLastMotionY = (int) ev.getY(newPointerIndex); + mVelocityTracker.clear(); + } + break; + } + case MotionEvent.ACTION_CANCEL: { + if (mIsScrolling) { + // Disable HW layers + mSv.decHwLayersRefCount("stackScroll"); + } + if (mSv.isScrollOutOfBounds()) { + // Animate the scroll back into bounds + // XXX: Make this animation a function of the velocity OR distance + mSv.animateBoundScroll(); + } + mActivePointerId = INACTIVE_POINTER_ID; + mIsScrolling = false; + mTotalScrollMotion = 0; + recycleVelocityTracker(); + break; + } + } + return true; + } + + /**** SwipeHelper Implementation ****/ + + @Override + public View getChildAtPosition(MotionEvent ev) { + return findViewAtPoint((int) ev.getX(), (int) ev.getY()); + } + + @Override + public boolean canChildBeDismissed(View v) { + return true; + } + + @Override + public void onBeginDrag(View v) { + // Enable HW layers + mSv.addHwLayersRefCount("swipeBegin"); + // Disable clipping with the stack while we are swiping + TaskView tv = (TaskView) v; + tv.setClipViewInStack(false); + // Disallow parents from intercepting touch events + final ViewParent parent = mSv.getParent(); + if (parent != null) { + parent.requestDisallowInterceptTouchEvent(true); + } + } + + @Override + public void onSwipeChanged(View v, float delta) { + // Do nothing + } + + @Override + public void onChildDismissed(View v) { + TaskView tv = (TaskView) v; + mSv.onTaskDismissed(tv); + + // Re-enable clipping with the stack (we will reuse this view) + tv.setClipViewInStack(true); + + // Disable HW layers + mSv.decHwLayersRefCount("swipeComplete"); + } + + @Override + public void onSnapBackCompleted(View v) { + // Re-enable clipping with the stack + TaskView tv = (TaskView) v; + tv.setClipViewInStack(true); + } + + @Override + public void onDragCancelled(View v) { + // Disable HW layers + mSv.decHwLayersRefCount("swipeCancelled"); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskThumbnailView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskThumbnailView.java index 8a9250a..c2b2094 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskThumbnailView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskThumbnailView.java @@ -17,15 +17,23 @@ package com.android.systemui.recents.views; import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Rect; import android.util.AttributeSet; +import android.view.View; import android.widget.ImageView; import com.android.systemui.recents.model.Task; /** The task thumbnail view */ public class TaskThumbnailView extends ImageView { + Task mTask; + // Task bar clipping + Rect mClipRect; + boolean mClipTaskBar = true; + public TaskThumbnailView(Context context) { this(context, null); } @@ -43,14 +51,42 @@ public class TaskThumbnailView extends ImageView { setScaleType(ScaleType.FIT_XY); } + @Override + public void draw(Canvas canvas) { + if (mClipTaskBar && (mClipRect != null)) { + int restoreCount = canvas.save(Canvas.CLIP_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); + canvas.clipRect(mClipRect); + super.draw(canvas); + canvas.restoreToCount(restoreCount); + } else { + super.draw(canvas); + } + } + + /** Updates the clip rect based on the given task bar. */ + void updateTaskBarClip(View taskBar) { + // If mClipTaskBar is unset first, then we don't bother setting mTaskBar + if (mClipTaskBar) { + int top = (int) Math.max(0, taskBar.getTranslationY() + + taskBar.getMeasuredHeight() - 1); + mClipRect = new Rect(0, top, getMeasuredWidth(), getMeasuredHeight()); + invalidate(0, 0, taskBar.getMeasuredWidth(), taskBar.getMeasuredHeight() + 1); + } + } + + /** Disables the task bar clipping. */ + void disableClipTaskBarView() { + mClipTaskBar = false; + if (mClipRect != null) { + invalidate(0, 0, mClipRect.width(), mClipRect.top); + } + } + /** Binds the thumbnail view to the task */ void rebindToTask(Task t, boolean animate) { mTask = t; if (t.thumbnail != null) { setImageBitmap(t.thumbnail); - if (animate) { - // XXX: Investigate how expensive it will be to create a second bitmap and crossfade - } } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index 5df5e4d..cfba74c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -16,11 +16,13 @@ package com.android.systemui.recents.views; +import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Outline; +import android.graphics.Paint; import android.graphics.Path; import android.graphics.Point; import android.graphics.Rect; @@ -28,9 +30,11 @@ import android.graphics.RectF; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; +import android.view.ViewPropertyAnimator; import android.view.animation.AccelerateInterpolator; import android.widget.FrameLayout; import com.android.systemui.R; +import com.android.systemui.recents.Console; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.model.Task; @@ -45,10 +49,10 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On public void onTaskAppInfoClicked(TaskView tv); public void onTaskFocused(TaskView tv); public void onTaskDismissed(TaskView tv); - - // public void onTaskViewReboundToTask(TaskView tv, Task t); } + RecentsConfiguration mConfig; + int mDim; int mMaxDim; TimeInterpolator mDimInterpolator = new AccelerateInterpolator(); @@ -59,11 +63,34 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On boolean mClipViewInStack; Point mLastTouchDown = new Point(); Path mRoundedRectClipPath = new Path(); + Rect mTmpRect = new Rect(); + Paint mLayerPaint = new Paint(); TaskThumbnailView mThumbnailView; TaskBarView mBarView; TaskViewCallbacks mCb; + // Optimizations + ValueAnimator.AnimatorUpdateListener mUpdateDimListener = + new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + updateDimOverlayFromScale(); + } + }; + Runnable mEnableThumbnailClip = new Runnable() { + @Override + public void run() { + mThumbnailView.updateTaskBarClip(mBarView); + } + }; + Runnable mDisableThumbnailClip = new Runnable() { + @Override + public void run() { + mThumbnailView.disableClipTaskBarView(); + } + }; + public TaskView(Context context) { this(context, null); @@ -79,20 +106,21 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); + mConfig = RecentsConfiguration.getInstance(); setWillNotDraw(false); + setDim(getDim()); } @Override protected void onFinishInflate() { - RecentsConfiguration config = RecentsConfiguration.getInstance(); - mMaxDim = config.taskStackMaxDim; + mMaxDim = mConfig.taskStackMaxDim; // By default, all views are clipped to other views in their stack mClipViewInStack = true; // Bind the views - mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail); mBarView = (TaskBarView) findViewById(R.id.task_view_bar); + mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail); if (mTaskDataLoaded) { onTaskDataLoaded(false); @@ -104,8 +132,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On super.onMeasure(widthMeasureSpec, heightMeasureSpec); // Update the rounded rect clip path - RecentsConfiguration config = RecentsConfiguration.getInstance(); - float radius = config.taskViewRoundedCornerRadiusPx; + float radius = mConfig.taskViewRoundedCornerRadiusPx; mRoundedRectClipPath.reset(); mRoundedRectClipPath.addRoundRect(new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight()), radius, radius, Path.Direction.CW); @@ -113,7 +140,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On // Update the outline Outline o = new Outline(); o.setRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight() - - config.taskViewShadowOutlineBottomInsetPx, radius); + mConfig.taskViewShadowOutlineBottomInsetPx, radius); setOutline(o); } @@ -139,52 +166,64 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On } /** Synchronizes this view's properties with the task's transform */ - void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform, - TaskViewTransform toTransform, int duration) { - RecentsConfiguration config = RecentsConfiguration.getInstance(); + void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int duration) { + if (Console.Enabled) { + Console.log(Constants.Log.UI.Draw, "[TaskView|updateViewPropertiesToTaskTransform]", + "duration: " + duration, Console.AnsiPurple); + } // Update the bar view - mBarView.updateViewPropertiesToTaskTransform(animateFromTransform, toTransform, duration); + mBarView.updateViewPropertiesToTaskTransform(toTransform, duration); - // Update this task view + // Check to see if any properties have changed, and update the task view if (duration > 0) { - if (animateFromTransform != null) { - setTranslationY(animateFromTransform.translationY); - if (Constants.DebugFlags.App.EnableShadows) { - setTranslationZ(animateFromTransform.translationZ); - } - setScaleX(animateFromTransform.scale); - setScaleY(animateFromTransform.scale); - setAlpha(animateFromTransform.alpha); + ViewPropertyAnimator anim = animate(); + boolean useLayers = false; + + // Animate to the final state + if (toTransform.hasTranslationYChangedFrom(getTranslationY())) { + anim.translationY(toTransform.translationY); } - if (Constants.DebugFlags.App.EnableShadows) { - animate().translationZ(toTransform.translationZ); + if (Constants.DebugFlags.App.EnableShadows && + toTransform.hasTranslationZChangedFrom(getTranslationZ())) { + anim.translationZ(toTransform.translationZ); } - animate().translationY(toTransform.translationY) - .scaleX(toTransform.scale) + if (toTransform.hasScaleChangedFrom(getScaleX())) { + anim.scaleX(toTransform.scale) .scaleY(toTransform.scale) - .alpha(toTransform.alpha) - .setDuration(duration) - .setInterpolator(config.fastOutSlowInInterpolator) - .withLayer() - .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - updateDimOverlayFromScale(); - } - }) - .start(); + .setUpdateListener(mUpdateDimListener); + useLayers = true; + } + if (toTransform.hasAlphaChangedFrom(getAlpha())) { + // Use layers if we animate alpha + anim.alpha(toTransform.alpha); + useLayers = true; + } + if (useLayers) { + anim.withLayer(); + } + anim.setStartDelay(toTransform.startDelay) + .setDuration(duration) + .setInterpolator(mConfig.fastOutSlowInInterpolator) + .start(); } else { - setTranslationY(toTransform.translationY); - if (Constants.DebugFlags.App.EnableShadows) { + // Set the changed properties + if (toTransform.hasTranslationYChangedFrom(getTranslationY())) { + setTranslationY(toTransform.translationY); + } + if (Constants.DebugFlags.App.EnableShadows && + toTransform.hasTranslationZChangedFrom(getTranslationZ())) { setTranslationZ(toTransform.translationZ); } - setScaleX(toTransform.scale); - setScaleY(toTransform.scale); - setAlpha(toTransform.alpha); + if (toTransform.hasScaleChangedFrom(getScaleX())) { + setScaleX(toTransform.scale); + setScaleY(toTransform.scale); + updateDimOverlayFromScale(); + } + if (toTransform.hasAlphaChangedFrom(getAlpha())) { + setAlpha(toTransform.alpha); + } } - updateDimOverlayFromScale(); - invalidate(); } /** Resets this view's properties */ @@ -197,6 +236,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On setScaleX(1f); setScaleY(1f); setAlpha(1f); + setDim(0); invalidate(); } @@ -208,6 +248,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On // Fade the view out and slide it away toTransform.alpha = 0f; toTransform.translationY += 200; + toTransform.translationZ = 0; } /** @@ -221,66 +262,176 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On /** Prepares this task view for the enter-recents animations. This is called earlier in the * first layout because the actual animation into recents may take a long time. */ - public void prepareAnimateOnEnterRecents() { - mBarView.setVisibility(View.INVISIBLE); + public void prepareEnterRecentsAnimation(boolean isTaskViewFrontMost, int offsetY, int offscreenY, + Rect taskRect) { + if (mConfig.launchedFromAppWithScreenshot) { + if (isTaskViewFrontMost) { + // Hide the task view as we are going to animate the full screenshot into view + // and then replace it with this view once we are done + setVisibility(View.INVISIBLE); + // Also hide the front most task bar view so we can animate it in + mBarView.prepareEnterRecentsAnimation(); + } else { + // Top align the task views + setTranslationY(offsetY); + setScaleX(1f); + setScaleY(1f); + } + + } else if (mConfig.launchedFromAppWithThumbnail) { + if (isTaskViewFrontMost) { + // Hide the front most task bar view so we can animate it in + mBarView.prepareEnterRecentsAnimation(); + // Set the dim to 0 so we can animate it in + setDim(0); + } + + } else if (mConfig.launchedFromHome) { + // Move the task view off screen (below) so we can animate it in + setTranslationY(offscreenY); + setTranslationZ(0); + setScaleX(1f); + setScaleY(1f); + } } /** Animates this task view as it enters recents */ - public void animateOnEnterRecents() { - RecentsConfiguration config = RecentsConfiguration.getInstance(); - mBarView.setVisibility(View.VISIBLE); - mBarView.setTranslationY(-mBarView.getMeasuredHeight()); - mBarView.animate() - .translationY(0) - .setStartDelay(config.taskBarEnterAnimDelay) - .setInterpolator(config.fastOutSlowInInterpolator) - .setDuration(config.taskBarEnterAnimDuration) + public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) { + TaskViewTransform transform = ctx.transform; + + if (mConfig.launchedFromAppWithScreenshot) { + if (ctx.isFrontMost) { + // Animate the full screenshot down first, before swapping with this task view + ctx.fullScreenshot.animateOnEnterRecents(ctx, new Runnable() { + @Override + public void run() { + // Animate the task bar of the first task view + mBarView.startEnterRecentsAnimation(0, mEnableThumbnailClip); + setVisibility(View.VISIBLE); + } + }); + } else { + // Animate the tasks down behind the full screenshot + animate() + .scaleX(transform.scale) + .scaleY(transform.scale) + .translationY(transform.translationY) + .setStartDelay(0) + .setUpdateListener(null) + .setInterpolator(mConfig.linearOutSlowInInterpolator) + .setDuration(475) + .withLayer() + .withEndAction(mEnableThumbnailClip) + .start(); + } + + } else if (mConfig.launchedFromAppWithThumbnail) { + if (ctx.isFrontMost) { + // Animate the task bar of the first task view + mBarView.startEnterRecentsAnimation(mConfig.taskBarEnterAnimDelay, mEnableThumbnailClip); + + // Animate the dim into view as well + ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", getDimOverlayFromScale()); + anim.setStartDelay(mConfig.taskBarEnterAnimDelay); + anim.setDuration(mConfig.taskBarEnterAnimDuration); + anim.setInterpolator(mConfig.fastOutLinearInInterpolator); + anim.start(); + } else { + mEnableThumbnailClip.run(); + } + + } else if (mConfig.launchedFromHome) { + // Animate the tasks up + int frontIndex = (ctx.stackViewCount - ctx.stackViewIndex - 1); + int delay = mConfig.taskBarEnterAnimDelay + + frontIndex * mConfig.taskViewEnterFromHomeDelay; + animate() + .scaleX(transform.scale) + .scaleY(transform.scale) + .translationY(transform.translationY) + .translationZ(transform.translationZ) + .setStartDelay(delay) + .setUpdateListener(null) + .setInterpolator(mConfig.quintOutInterpolator) + .setDuration(mConfig.taskViewEnterFromHomeDuration) + .withLayer() + .withEndAction(mEnableThumbnailClip) + .start(); + } + } + + /** Animates this task view as it leaves recents by pressing home. */ + public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) { + animate() + .translationY(ctx.offscreenTranslationY) + .setStartDelay(0) + .setUpdateListener(null) + .setInterpolator(mConfig.fastOutLinearInInterpolator) + .setDuration(mConfig.taskViewExitToHomeDuration) .withLayer() + .withEndAction(ctx.postAnimationTrigger.decrementAsRunnable()) .start(); + ctx.postAnimationTrigger.increment(); } /** Animates this task view as it exits recents */ - public void animateOnLeavingRecents(final Runnable r) { - RecentsConfiguration config = RecentsConfiguration.getInstance(); - mBarView.animate() - .translationY(-mBarView.getMeasuredHeight()) - .setStartDelay(0) - .setInterpolator(config.fastOutLinearInInterpolator) - .setDuration(config.taskBarExitAnimDuration) - .withLayer() - .withEndAction(new Runnable() { - @Override - public void run() { - post(r); - } - }) - .start(); + public void startLaunchTaskAnimation(final Runnable r, boolean isLaunchingTask) { + if (isLaunchingTask) { + // Disable the thumbnail clip and animate the bar out + mBarView.startLaunchTaskAnimation(mDisableThumbnailClip, r); + + // Animate the dim + if (mDim > 0) { + ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", 0); + anim.setDuration(mConfig.taskBarExitAnimDuration); + anim.setInterpolator(mConfig.fastOutLinearInInterpolator); + anim.start(); + } + } else { + // Hide the dismiss button + mBarView.startLaunchTaskDismissAnimation(); + } } /** Animates the deletion of this task view */ - public void animateRemoval(final Runnable r) { + public void startDeleteTaskAnimation(final Runnable r) { // Disabling clipping with the stack while the view is animating away setClipViewInStack(false); - RecentsConfiguration config = RecentsConfiguration.getInstance(); - animate().translationX(config.taskViewRemoveAnimTranslationXPx) + animate().translationX(mConfig.taskViewRemoveAnimTranslationXPx) .alpha(0f) .setStartDelay(0) - .setInterpolator(config.fastOutSlowInInterpolator) - .setDuration(config.taskViewRemoveAnimDuration) + .setUpdateListener(null) + .setInterpolator(mConfig.fastOutSlowInInterpolator) + .setDuration(mConfig.taskViewRemoveAnimDuration) .withLayer() .withEndAction(new Runnable() { @Override public void run() { - post(r); + // We just throw this into a runnable because starting a view property + // animation using layers can cause inconsisten results if we try and + // update the layers while the animation is running. In some cases, + // the runnabled passed in may start an animation which also uses layers + // so we defer all this by posting this. + r.run(); // Re-enable clipping with the stack (we will reuse this view) - setClipViewInStack(false); + setClipViewInStack(true); } }) .start(); } + /** Animates this task view if the user does not interact with the stack after a certain time. */ + public void startNoUserInteractionAnimation() { + mBarView.startNoUserInteractionAnimation(); + } + + /** Mark this task view that the user does has not interacted with the stack after a certain time. */ + public void setNoUserInteractionState() { + mBarView.setNoUserInteractionState(); + } + /** Returns the rect we want to clip (it may not be the full rect) */ Rect getClippingRect(Rect outRect) { getHitRect(outRect); @@ -292,12 +443,14 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On /** Enable the hw layers on this task view */ void enableHwLayers() { - mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, null); + mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, mLayerPaint); + mBarView.enableHwLayers(); } /** Disable the hw layers on this task view */ void disableHwLayers() { - mThumbnailView.setLayerType(View.LAYER_TYPE_NONE, null); + mThumbnailView.setLayerType(View.LAYER_TYPE_NONE, mLayerPaint); + mBarView.disableHwLayers(); } /** @@ -305,7 +458,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On * view. */ boolean shouldClipViewInStack() { - return mClipViewInStack; + return mClipViewInStack && (getVisibility() == View.VISIBLE); } /** Sets whether this view should be clipped, or clipped against. */ @@ -313,28 +466,44 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On if (clip != mClipViewInStack) { mClipViewInStack = clip; if (getParent() instanceof View) { - Rect r = new Rect(); - getHitRect(r); - ((View) getParent()).invalidate(r); + getHitRect(mTmpRect); + ((View) getParent()).invalidate(mTmpRect); } } } - /** Update the dim as a function of the scale of this view. */ - void updateDimOverlayFromScale() { + /** Returns the current dim. */ + public void setDim(int dim) { + mDim = dim; + postInvalidateOnAnimation(); + } + + /** Returns the current dim. */ + public int getDim() { + return mDim; + } + + /** Compute the dim as a function of the scale of this view. */ + int getDimOverlayFromScale() { float minScale = Constants.Values.TaskStackView.StackPeekMinScale; float scaleRange = 1f - minScale; float dim = (1f - getScaleX()) / scaleRange; dim = mDimInterpolator.getInterpolation(Math.min(dim, 1f)); - mDim = Math.max(0, Math.min(mMaxDim, (int) (dim * 255))); + return Math.max(0, Math.min(mMaxDim, (int) (dim * 255))); + } + + /** Update the dim as a function of the scale of this view. */ + void updateDimOverlayFromScale() { + setDim(getDimOverlayFromScale()); } @Override public void draw(Canvas canvas) { + int restoreCount = canvas.save(Canvas.CLIP_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); // Apply the rounded rect clip path on the whole view canvas.clipPath(mRoundedRectClipPath); - super.draw(canvas); + canvas.restoreToCount(restoreCount); // Apply the dim if necessary if (mDim > 0) { @@ -391,8 +560,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On mBarView.mApplicationIcon.setOnClickListener(this); mBarView.mDismissButton.setOnClickListener(this); if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) { - RecentsConfiguration config = RecentsConfiguration.getInstance(); - if (config.developerOptionsEnabled) { + if (mConfig.developerOptionsEnabled) { mBarView.mApplicationIcon.setOnLongClickListener(this); } } @@ -418,19 +586,25 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On } @Override - public void onClick(View v) { - if (v == mBarView.mApplicationIcon) { - mCb.onTaskIconClicked(this); - } else if (v == mBarView.mDismissButton) { - // Animate out the view and call the callback - final TaskView tv = this; - animateRemoval(new Runnable() { - @Override - public void run() { - mCb.onTaskDismissed(tv); + public void onClick(final View v) { + // We purposely post the handler delayed to allow for the touch feedback to draw + final TaskView tv = this; + postDelayed(new Runnable() { + @Override + public void run() { + if (v == mBarView.mApplicationIcon) { + mCb.onTaskIconClicked(tv); + } else if (v == mBarView.mDismissButton) { + // Animate out the view and call the callback + startDeleteTaskAnimation(new Runnable() { + @Override + public void run() { + mCb.onTaskDismissed(tv); + } + }); } - }); - } + } + }, 125); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java index 3c3ebd7..b351b03 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java @@ -21,6 +21,7 @@ import android.graphics.Rect; /* The transform state for a task view */ public class TaskViewTransform { + public int startDelay = 0; public int translationY = 0; public int translationZ = 0; public float scale = 1f; @@ -28,13 +29,14 @@ public class TaskViewTransform { public float dismissAlpha = 1f; public boolean visible = false; public Rect rect = new Rect(); - float t; + float t = 0f; public TaskViewTransform() { // Do nothing } public TaskViewTransform(TaskViewTransform o) { + startDelay = o.startDelay; translationY = o.translationY; translationZ = o.translationZ; scale = o.scale; @@ -45,9 +47,40 @@ public class TaskViewTransform { t = o.t; } + /** Resets the current transform */ + public void reset() { + startDelay = 0; + translationY = 0; + translationZ = 0; + scale = 1f; + alpha = 1f; + dismissAlpha = 1f; + visible = false; + rect.setEmpty(); + t = 0f; + } + + /** Convenience functions to compare against current property values */ + public boolean hasAlphaChangedFrom(float v) { + return (Float.compare(alpha, v) != 0); + } + public boolean hasDismissAlphaChangedFrom(float v) { + return (Float.compare(dismissAlpha, v) != 0); + } + public boolean hasScaleChangedFrom(float v) { + return (Float.compare(scale, v) != 0); + } + public boolean hasTranslationYChangedFrom(float v) { + return (Float.compare(translationY, v) != 0); + } + public boolean hasTranslationZChangedFrom(float v) { + return (Float.compare(translationZ, v) != 0); + } + @Override public String toString() { - return "TaskViewTransform y: " + translationY + " scale: " + scale + " alpha: " + alpha + - " visible: " + visible + " rect: " + rect + " dismissAlpha: " + dismissAlpha; + return "TaskViewTransform delay: " + startDelay + " y: " + translationY + " z: " + translationZ + + " scale: " + scale + " alpha: " + alpha + " visible: " + visible + " rect: " + rect + + " dismissAlpha: " + dismissAlpha; } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java new file mode 100644 index 0000000..13407aa --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.recents.views; + +import android.graphics.Rect; +import com.android.systemui.recents.ReferenceCountedTrigger; + +/* Common code related to view animations */ +public class ViewAnimation { + + /* The animation context for a task view animation into Recents */ + public static class TaskViewEnterContext { + // The full screenshot view that we are animating down + FullscreenTransitionOverlayView fullScreenshot; + // The transform of the current task view + TaskViewTransform transform; + // The stack rect that the transform is relative to + Rect stackRectSansPeek; + // The task rect + Rect taskRect; + // The view index of the current task view + int stackViewIndex; + // The total number of task views + int stackViewCount; + // Whether this is the front most task view + boolean isFrontMost; + + public TaskViewEnterContext(FullscreenTransitionOverlayView fss) { + fullScreenshot = fss; + } + } + + /* The animation context for a task view animation out of Recents */ + public static class TaskViewExitContext { + // A trigger to run some logic when all the animations complete. This works around the fact + // that it is difficult to coordinate ViewPropertyAnimators + ReferenceCountedTrigger postAnimationTrigger; + // The translationY to apply to a TaskView to move it off screen + int offscreenTranslationY; + + public TaskViewExitContext(ReferenceCountedTrigger t) { + postAnimationTrigger = t; + } + } + +} diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java b/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java index d67e7cb..a3b10f2 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java +++ b/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java @@ -21,8 +21,16 @@ import com.android.systemui.R; import android.app.ActivityManagerNative; import android.content.Context; import android.content.pm.UserInfo; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Shader; +import android.os.Handler; import android.os.RemoteException; import android.os.UserManager; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; @@ -43,15 +51,18 @@ import java.util.List; /** * A quick and dirty view to show a user switcher. */ -public class UserSwitcherHostView extends FrameLayout implements ListView.OnItemClickListener { +public class UserSwitcherHostView extends FrameLayout + implements ListView.OnItemClickListener, View.OnClickListener { private static final String TAG = "UserSwitcherDialog"; private ArrayList<UserInfo> mUserInfo = new ArrayList<UserInfo>(); + private UserInfo mGuestUser; private Adapter mAdapter = new Adapter(); private UserManager mUserManager; private Runnable mFinishRunnable; private ListView mListView; + private boolean mGuestUserEnabled; public UserSwitcherHostView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); @@ -60,6 +71,9 @@ public class UserSwitcherHostView extends FrameLayout implements ListView.OnItem return; } mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + + mGuestUserEnabled = Settings.Global.getInt(context.getContentResolver(), + Settings.Global.GUEST_USER_ENABLED, 0) == 1; } public UserSwitcherHostView(Context context, AttributeSet attrs) { @@ -80,7 +94,39 @@ public class UserSwitcherHostView extends FrameLayout implements ListView.OnItem @Override public void onItemClick(AdapterView<?> l, View v, int position, long id) { - int userId = mAdapter.getItem(position).id; + // Last item is the guest + if (position == mUserInfo.size()) { + postDelayed(new Runnable() { + public void run() { + switchToGuestUser(); + } + }, 100); + } else { + final int userId = mAdapter.getItem(position).id; + postDelayed(new Runnable() { + public void run() { + switchUser(userId); + } + }, 100); + } + } + + @Override + public void onClick(View v) { + // Delete was clicked + postDelayed(new Runnable() { + public void run() { + if (mGuestUser != null) { + switchUser(0); + mUserManager.removeUser(mGuestUser.id); + mGuestUser = null; + refreshUsers(); + } + } + }, 100); + } + + private void switchUser(int userId) { try { WindowManagerGlobal.getWindowManagerService().lockNow(null); ActivityManagerNative.getDefault().switchUser(userId); @@ -90,6 +136,15 @@ public class UserSwitcherHostView extends FrameLayout implements ListView.OnItem } } + private void switchToGuestUser() { + if (mGuestUser == null) { + // No guest user. Create one. + mGuestUser = mUserManager.createGuest(mContext, + mContext.getResources().getString(R.string.guest_nickname)); + } + switchUser(mGuestUser.id); + } + private void finish() { if (mFinishRunnable != null) { mFinishRunnable.run(); @@ -119,9 +174,12 @@ public class UserSwitcherHostView extends FrameLayout implements ListView.OnItem public void refreshUsers() { mUserInfo.clear(); + mGuestUser = null; List<UserInfo> users = mUserManager.getUsers(true); for (UserInfo user : users) { - if (!user.isManagedProfile()) { + if (user.isGuest()) { + mGuestUser = user; + } else if (!user.isManagedProfile()) { mUserInfo.add(user); } } @@ -132,17 +190,25 @@ public class UserSwitcherHostView extends FrameLayout implements ListView.OnItem @Override public int getCount() { - return mUserInfo.size(); + return mUserInfo.size() + (mGuestUserEnabled ? 1 : 0); } @Override public UserInfo getItem(int position) { - return mUserInfo.get(position); + if (position < mUserInfo.size()) { + return mUserInfo.get(position); + } else { + return mGuestUser; + } } @Override public long getItemId(int position) { - return getItem(position).serialNumber; + if (position < mUserInfo.size()) { + return getItem(position).serialNumber; + } else { + return mGuestUser != null ? mGuestUser.serialNumber : -1; + } } @Override @@ -161,18 +227,46 @@ public class UserSwitcherHostView extends FrameLayout implements ListView.OnItem ViewHolder h = new ViewHolder(); h.name = (TextView) v.findViewById(R.id.user_name); h.picture = (ImageView) v.findViewById(R.id.user_picture); + h.delete = (ImageView) v.findViewById(R.id.user_delete); v.setTag(h); return v; } private void bindView(ViewHolder h, UserInfo item) { - h.name.setText(item.name); - h.picture.setImageBitmap(mUserManager.getUserIcon(item.id)); + if (item != null) { + h.name.setText(item.name); + h.picture.setImageBitmap(circularClip(mUserManager.getUserIcon(item.id))); + h.delete.setVisibility(item.isGuest() ? View.VISIBLE : View.GONE); + h.delete.setOnClickListener(UserSwitcherHostView.this); + if (item.isGuest()) { + h.picture.setImageResource(R.drawable.ic_account_circle); + } + } else { + h.name.setText(R.string.guest_new_guest); + h.picture.setImageResource(R.drawable.ic_account_circle); + h.delete.setVisibility(View.GONE); + } + } + + private Bitmap circularClip(Bitmap input) { + if (input == null) { + return null; + } + Bitmap output = Bitmap.createBitmap(input.getWidth(), + input.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(output); + final Paint paint = new Paint(); + paint.setShader(new BitmapShader(input, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); + paint.setAntiAlias(true); + canvas.drawCircle(input.getWidth() / 2, input.getHeight() / 2, input.getWidth() / 2, + paint); + return output; } class ViewHolder { TextView name; ImageView picture; + ImageView delete; } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java index 8d19f50..f6f78e9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java @@ -119,6 +119,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView private NotificationBackgroundView mBackgroundNormal; private NotificationBackgroundView mBackgroundDimmed; + private NotificationScrimView mScrimView; private ObjectAnimator mBackgroundAnimator; private RectF mAppearAnimationRect = new RectF(); private PorterDuffColorFilter mAppearAnimationFilter; @@ -153,6 +154,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mBackgroundDimmed = (NotificationBackgroundView) findViewById(R.id.backgroundDimmed); updateBackground(); updateBackgroundResources(); + mScrimView = (NotificationScrimView) findViewById(R.id.scrim_view); } private final Runnable mTapTimeoutRunnable = new Runnable() { @@ -379,6 +381,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView setPivotY(actualHeight / 2); mBackgroundNormal.setActualHeight(actualHeight); mBackgroundDimmed.setActualHeight(actualHeight); + mScrimView.setActualHeight(actualHeight); } @Override @@ -386,6 +389,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView super.setClipTopAmount(clipTopAmount); mBackgroundNormal.setClipTopAmount(clipTopAmount); mBackgroundDimmed.setClipTopAmount(clipTopAmount); + mScrimView.setClipTopAmount(clipTopAmount); } @Override @@ -405,6 +409,11 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } } + @Override + public void setScrimAmount(float scrimAmount) { + mScrimView.setAlpha(scrimAmount); + } + private void startAppearAnimation(boolean isAppearing, float translationDirection, long delay, final Runnable onFinishedRunnable) { if (mAppearAnimator != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index b94493e..c621f31 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -89,11 +89,11 @@ import java.util.Locale; import static com.android.keyguard.KeyguardHostView.OnDismissAction; public abstract class BaseStatusBar extends SystemUI implements - CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener { + CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener, + RecentsComponent.Callbacks { 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 = true; protected static final int MSG_SHOW_RECENT_APPS = 1019; protected static final int MSG_HIDE_RECENT_APPS = 1020; @@ -297,7 +297,7 @@ public abstract class BaseStatusBar extends SystemUI implements @Override public void run() { for (StatusBarNotification sbn : notifications) { - addNotificationInternal(sbn, currentRanking); + addNotification(sbn, currentRanking); } } }); @@ -324,16 +324,16 @@ public abstract class BaseStatusBar extends SystemUI implements // wasn't a group child, remove the old instance. // Otherwise just update the ranking. if (isUpdate) { - removeNotificationInternal(sbn.getKey(), rankingMap); + removeNotification(sbn.getKey(), rankingMap); } else { - updateRankingInternal(rankingMap); + updateNotificationRanking(rankingMap); } return; } if (isUpdate) { - updateNotificationInternal(sbn, rankingMap); + updateNotification(sbn, rankingMap); } else { - addNotificationInternal(sbn, rankingMap); + addNotification(sbn, rankingMap); } } }); @@ -346,7 +346,7 @@ public abstract class BaseStatusBar extends SystemUI implements mHandler.post(new Runnable() { @Override public void run() { - removeNotificationInternal(sbn.getKey(), rankingMap); + removeNotification(sbn.getKey(), rankingMap); } }); } @@ -357,7 +357,7 @@ public abstract class BaseStatusBar extends SystemUI implements mHandler.post(new Runnable() { @Override public void run() { - updateRankingInternal(rankingMap); + updateNotificationRanking(rankingMap); } }); } @@ -404,6 +404,7 @@ public abstract class BaseStatusBar extends SystemUI implements ServiceManager.getService(Context.STATUS_BAR_SERVICE)); mRecents = getComponent(RecentsComponent.class); + mRecents.setCallback(this); mLocale = mContext.getResources().getConfiguration().locale; mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale); @@ -412,14 +413,12 @@ public abstract class BaseStatusBar extends SystemUI implements // Connect in to the status bar manager service StatusBarIconList iconList = new StatusBarIconList(); - 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, notifications, - switches, binders); + mBarService.registerStatusBar(mCommandQueue, iconList, switches, binders); } catch (RemoteException ex) { // If the system process isn't there we're doomed anyway. } @@ -445,19 +444,12 @@ public abstract class BaseStatusBar extends SystemUI implements } // 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 { - N = notifications.size(); - for (int i=0; i<N; i++) { - addNotification(notifications.get(i)); - } + try { + mNotificationListener.registerAsSystemService( + new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()), + UserHandle.USER_ALL); + } catch (RemoteException e) { + Log.e(TAG, "Unable to register notification listener", e); } @@ -787,6 +779,11 @@ public abstract class BaseStatusBar extends SystemUI implements } } + @Override + public void onVisibilityChanged(boolean visible) { + // Do nothing + } + public abstract void resetHeadsUpDecayTimer(); public abstract void scheduleHeadsUpOpen(); @@ -1187,7 +1184,7 @@ public abstract class BaseStatusBar extends SystemUI implements * WARNING: this will call back into us. Don't hold any locks. */ void handleNotificationError(StatusBarNotification n, String message) { - removeNotification(n.getKey()); + removeNotification(n.getKey(), null); try { mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(), n.getInitialPid(), message, n.getUserId()); @@ -1323,34 +1320,11 @@ public abstract class BaseStatusBar extends SystemUI implements protected abstract void updateExpandedViewPos(int expandedPosition); protected abstract boolean shouldDisableNavbarGestures(); - @Override - public void addNotification(StatusBarNotification notification) { - if (!USE_NOTIFICATION_LISTENER) { - addNotificationInternal(notification, null); - } - } - - public abstract void addNotificationInternal(StatusBarNotification notification, + public abstract void addNotification(StatusBarNotification notification, RankingMap ranking); - - protected abstract void updateRankingInternal(RankingMap ranking); - - @Override - public void removeNotification(String key) { - if (!USE_NOTIFICATION_LISTENER) { - removeNotificationInternal(key, null); - } - } - - public abstract void removeNotificationInternal(String key, RankingMap ranking); - - public void updateNotification(StatusBarNotification notification) { - if (!USE_NOTIFICATION_LISTENER) { - updateNotificationInternal(notification, null); - } - } - - public void updateNotificationInternal(StatusBarNotification notification, RankingMap ranking) { + protected abstract void updateNotificationRanking(RankingMap ranking); + public abstract void removeNotification(String key, RankingMap ranking); + public void updateNotification(StatusBarNotification notification, RankingMap ranking) { if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")"); final String key = notification.getKey(); @@ -1467,7 +1441,7 @@ public abstract class BaseStatusBar extends SystemUI implements } else { if (shouldInterrupt && alertAgain) { removeNotificationViews(key, ranking); - addNotificationInternal(notification, ranking); //this will pop the headsup + addNotification(notification, ranking); //this will pop the headsup } else { updateNotificationViews(oldEntry, notification); } @@ -1507,7 +1481,7 @@ public abstract class BaseStatusBar extends SystemUI implements if (shouldInterrupt && alertAgain) { if (DEBUG) Log.d(TAG, "reposting to invoke heads up for key: " + key); removeNotificationViews(key, ranking); - addNotificationInternal(notification, ranking); //this will pop the headsup + addNotification(notification, ranking); //this will pop the headsup } else { if (DEBUG) Log.d(TAG, "rebuilding update in place for key: " + key); removeNotificationViews(key, ranking); @@ -1665,12 +1639,10 @@ public abstract class BaseStatusBar extends SystemUI implements mWindowManager.removeViewImmediate(mSearchPanelView); } mContext.unregisterReceiver(mBroadcastReceiver); - if (USE_NOTIFICATION_LISTENER) { - try { - mNotificationListener.unregisterAsSystemService(); - } catch (RemoteException e) { - // Ignore. - } + try { + mNotificationListener.unregisterAsSystemService(); + } catch (RemoteException e) { + // Ignore. } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index aaeadb6..2b61f09 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -41,23 +41,20 @@ public class CommandQueue extends IStatusBar.Stub { private static final int OP_REMOVE_ICON = 2; private static final int MSG_ICON = 1 << MSG_SHIFT; - private static final int MSG_ADD_NOTIFICATION = 2 << MSG_SHIFT; - private static final int MSG_UPDATE_NOTIFICATION = 3 << MSG_SHIFT; - private static final int MSG_REMOVE_NOTIFICATION = 4 << MSG_SHIFT; - private static final int MSG_DISABLE = 5 << MSG_SHIFT; - private static final int MSG_EXPAND_NOTIFICATIONS = 6 << MSG_SHIFT; - private static final int MSG_COLLAPSE_PANELS = 7 << MSG_SHIFT; - private static final int MSG_EXPAND_SETTINGS = 8 << MSG_SHIFT; - private static final int MSG_SET_SYSTEMUI_VISIBILITY = 9 << MSG_SHIFT; - private static final int MSG_TOP_APP_WINDOW_CHANGED = 10 << MSG_SHIFT; - private static final int MSG_SHOW_IME_BUTTON = 11 << MSG_SHIFT; - private static final int MSG_SET_HARD_KEYBOARD_STATUS = 12 << MSG_SHIFT; - private static final int MSG_TOGGLE_RECENT_APPS = 13 << MSG_SHIFT; - private static final int MSG_PRELOAD_RECENT_APPS = 14 << MSG_SHIFT; - private static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 15 << MSG_SHIFT; - private static final int MSG_SET_WINDOW_STATE = 16 << MSG_SHIFT; - private static final int MSG_SHOW_RECENT_APPS = 17 << MSG_SHIFT; - private static final int MSG_HIDE_RECENT_APPS = 18 << MSG_SHIFT; + private static final int MSG_DISABLE = 2 << MSG_SHIFT; + private static final int MSG_EXPAND_NOTIFICATIONS = 3 << MSG_SHIFT; + private static final int MSG_COLLAPSE_PANELS = 4 << MSG_SHIFT; + private static final int MSG_EXPAND_SETTINGS = 5 << MSG_SHIFT; + private static final int MSG_SET_SYSTEMUI_VISIBILITY = 6 << MSG_SHIFT; + private static final int MSG_TOP_APP_WINDOW_CHANGED = 7 << MSG_SHIFT; + private static final int MSG_SHOW_IME_BUTTON = 8 << MSG_SHIFT; + private static final int MSG_SET_HARD_KEYBOARD_STATUS = 9 << MSG_SHIFT; + private static final int MSG_TOGGLE_RECENT_APPS = 10 << MSG_SHIFT; + private static final int MSG_PRELOAD_RECENT_APPS = 11 << MSG_SHIFT; + private static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 12 << MSG_SHIFT; + private static final int MSG_SET_WINDOW_STATE = 13 << MSG_SHIFT; + private static final int MSG_SHOW_RECENT_APPS = 14 << MSG_SHIFT; + private static final int MSG_HIDE_RECENT_APPS = 15 << MSG_SHIFT; public static final int FLAG_EXCLUDE_NONE = 0; public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; @@ -80,9 +77,6 @@ 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(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); @@ -123,26 +117,6 @@ public class CommandQueue extends IStatusBar.Stub { } } - @Override - public void addNotification(StatusBarNotification notification) { - synchronized (mList) { - mHandler.obtainMessage(MSG_ADD_NOTIFICATION, 0, 0, notification).sendToTarget(); - } - } - - @Override - public void updateNotification(StatusBarNotification notification) { - synchronized (mList) { - mHandler.obtainMessage(MSG_UPDATE_NOTIFICATION, 0, 0, notification).sendToTarget(); - } - } - - public void removeNotification(String key) { - synchronized (mList) { - mHandler.obtainMessage(MSG_REMOVE_NOTIFICATION, 0, 0, key).sendToTarget(); - } - } - public void disable(int state) { synchronized (mList) { mHandler.removeMessages(MSG_DISABLE); @@ -279,18 +253,6 @@ public class CommandQueue extends IStatusBar.Stub { } break; } - case MSG_ADD_NOTIFICATION: { - mCallbacks.addNotification((StatusBarNotification) msg.obj); - break; - } - case MSG_UPDATE_NOTIFICATION: { - mCallbacks.updateNotification((StatusBarNotification) msg.obj); - break; - } - case MSG_REMOVE_NOTIFICATION: { - mCallbacks.removeNotification((String) msg.obj); - break; - } case MSG_DISABLE: mCallbacks.disable(msg.arg1); break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index 5bad602..5981898 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -212,13 +212,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { return mShowingPublic ? mRowMinHeight : mMaxExpandHeight; } - /** - * @return the potential height this view could expand in addition. - */ - public int getExpandPotential() { - return getIntrinsicHeight() - getActualHeight(); - } - @Override public boolean isContentExpandable() { NotificationContentView showingLayout = getShowingLayout(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java index ac2537c..4d4a8ab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java @@ -223,6 +223,8 @@ public abstract class ExpandableView extends FrameLayout { public abstract void performAddAnimation(long delay); + public abstract void setScrimAmount(float scrimAmount); + /** * A listener notifying when {@link #getActualHeight} changes. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java deleted file mode 100644 index bfa74fa..0000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar; - -import android.app.Notification; -import android.content.Context; -import android.os.Process; -import android.provider.Settings; -import android.service.notification.NotificationListenerService.Ranking; -import android.service.notification.NotificationListenerService.RankingMap; -import android.service.notification.StatusBarNotification; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.view.View; - -import com.android.systemui.R; -import com.android.systemui.statusbar.NotificationData.Entry; -import com.android.systemui.statusbar.phone.PhoneStatusBar; - -public class InterceptedNotifications { - private static final String TAG = "InterceptedNotifications"; - private static final String SYNTHETIC_KEY = "InterceptedNotifications.SYNTHETIC_KEY"; - - private final Context mContext; - private final PhoneStatusBar mBar; - private final ArrayMap<String, StatusBarNotification> mIntercepted - = new ArrayMap<String, StatusBarNotification>(); - private final ArraySet<String> mReleased = new ArraySet<String>(); - - private String mSynKey; - - public InterceptedNotifications(Context context, PhoneStatusBar bar) { - mContext = context; - mBar = bar; - } - - public void releaseIntercepted() { - final int n = mIntercepted.size(); - for (int i = 0; i < n; i++) { - final StatusBarNotification sbn = mIntercepted.valueAt(i); - mReleased.add(sbn.getKey()); - mBar.displayNotification(sbn, null); - } - mIntercepted.clear(); - updateSyntheticNotification(); - } - - public boolean tryIntercept(StatusBarNotification notification, RankingMap rankingMap) { - if (rankingMap == null) return false; - if (shouldDisplayIntercepted()) return false; - if (mReleased.contains(notification.getKey())) return false; - Ranking ranking = rankingMap.getRanking(notification.getKey()); - if (!ranking.isInterceptedByDoNotDisturb()) return false; - mIntercepted.put(notification.getKey(), notification); - updateSyntheticNotification(); - return true; - } - - public void retryIntercepts(RankingMap ranking) { - if (ranking == null) return; - - final int N = mIntercepted.size(); - final ArraySet<String> removed = new ArraySet<String>(N); - for (int i = 0; i < N; i++) { - final StatusBarNotification sbn = mIntercepted.valueAt(i); - if (!tryIntercept(sbn, ranking)) { - removed.add(sbn.getKey()); - mBar.displayNotification(sbn, ranking); - } - } - if (!removed.isEmpty()) { - mIntercepted.removeAll(removed); - updateSyntheticNotification(); - } - } - - public void remove(String key) { - if (mIntercepted.remove(key) != null) { - updateSyntheticNotification(); - } - mReleased.remove(key); - } - - public boolean isSyntheticEntry(Entry ent) { - return ent.key.equals(mSynKey); - } - - private boolean shouldDisplayIntercepted() { - return Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.DISPLAY_INTERCEPTED_NOTIFICATIONS, 0) != 0; - } - - private void updateSyntheticNotification() { - if (mIntercepted.isEmpty()) { - if (mSynKey != null) { - mBar.removeNotificationInternal(mSynKey, null); - mSynKey = null; - } - return; - } - final Notification n = new Notification.Builder(mContext) - .setSmallIcon(R.drawable.ic_notify_zen) - .setContentTitle(mContext.getResources().getQuantityString( - R.plurals.zen_mode_notification_title, - mIntercepted.size(), mIntercepted.size())) - .setContentText(mContext.getString(R.string.zen_mode_notification_text)) - .setOngoing(true) - .build(); - final StatusBarNotification sbn = new StatusBarNotification(mContext.getPackageName(), - mContext.getBasePackageName(), - TAG.hashCode(), TAG, Process.myUid(), Process.myPid(), 0, n, - mBar.getCurrentUserHandle()); - if (mSynKey == null) { - mSynKey = sbn.getKey(); - mBar.displayNotification(sbn, null); - } else { - mBar.updateNotificationInternal(sbn, null); - } - final NotificationData.Entry entry = mBar.mNotificationData.findByKey(mSynKey); - entry.row.setOnClickListener(mSynClickListener); - } - - private final View.OnClickListener mSynClickListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - releaseIntercepted(); - } - }; -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java index 5cde979..f919501 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java @@ -17,12 +17,16 @@ package com.android.systemui.statusbar; import android.content.Context; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.util.AttributeSet; -import android.view.Gravity; import android.view.View; - +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; import android.widget.FrameLayout; + import com.android.systemui.R; /** @@ -32,6 +36,8 @@ import com.android.systemui.R; */ public class NotificationContentView extends FrameLayout { + private static final long ANIMATION_DURATION_LENGTH = 170; + private final Rect mClipBounds = new Rect(); private View mContractedChild; @@ -41,10 +47,17 @@ public class NotificationContentView extends FrameLayout { private int mClipTopAmount; private int mActualHeight; + private final Interpolator mLinearInterpolator = new LinearInterpolator(); + + private boolean mContractedVisible = true; + + private Paint mFadePaint = new Paint(); + public NotificationContentView(Context context, AttributeSet attrs) { super(context, attrs); mSmallHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height); mActualHeight = mSmallHeight; + mFadePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD)); } @Override @@ -60,7 +73,7 @@ public class NotificationContentView extends FrameLayout { sanitizeContractedLayoutParams(child); addView(child); mContractedChild = child; - selectLayout(); + selectLayout(false /* animate */, true /* force */); } public void setExpandedChild(View child) { @@ -69,12 +82,12 @@ public class NotificationContentView extends FrameLayout { } addView(child); mExpandedChild = child; - selectLayout(); + selectLayout(false /* animate */, true /* force */); } public void setActualHeight(int actualHeight) { mActualHeight = actualHeight; - selectLayout(); + selectLayout(true /* animate */, false /* force */); updateClipping(); } @@ -104,26 +117,60 @@ public class NotificationContentView extends FrameLayout { contractedChild.setLayoutParams(lp); } - private void selectLayout() { - if (mActualHeight <= mSmallHeight || mExpandedChild == null) { - if (mContractedChild != null && mContractedChild.getVisibility() != View.VISIBLE) { - mContractedChild.setVisibility(View.VISIBLE); - } - if (mExpandedChild != null && mExpandedChild.getVisibility() != View.INVISIBLE) { - mExpandedChild.setVisibility(View.INVISIBLE); - } - } else { - if (mExpandedChild.getVisibility() != View.VISIBLE) { - mExpandedChild.setVisibility(View.VISIBLE); - } - if (mContractedChild != null && mContractedChild.getVisibility() != View.INVISIBLE) { - mContractedChild.setVisibility(View.INVISIBLE); + private void selectLayout(boolean animate, boolean force) { + if (mContractedChild == null) { + return; + } + boolean showContractedChild = showContractedChild(); + if (showContractedChild != mContractedVisible || force) { + if (animate && mExpandedChild != null) { + runSwitchAnimation(showContractedChild); + } else if (mExpandedChild != null) { + mContractedChild.setVisibility(showContractedChild ? View.VISIBLE : View.INVISIBLE); + mContractedChild.setAlpha(showContractedChild ? 1f : 0f); + mExpandedChild.setVisibility(showContractedChild ? View.INVISIBLE : View.VISIBLE); + mExpandedChild.setAlpha(showContractedChild ? 0f : 1f); } } + mContractedVisible = showContractedChild; + } + + private void runSwitchAnimation(final boolean showContractedChild) { + mContractedChild.setVisibility(View.VISIBLE); + mExpandedChild.setVisibility(View.VISIBLE); + mContractedChild.setLayerType(LAYER_TYPE_HARDWARE, mFadePaint); + mExpandedChild.setLayerType(LAYER_TYPE_HARDWARE, mFadePaint); + setLayerType(LAYER_TYPE_HARDWARE, null); + mContractedChild.animate() + .alpha(showContractedChild ? 1f : 0f) + .setDuration(ANIMATION_DURATION_LENGTH) + .setInterpolator(mLinearInterpolator); + mExpandedChild.animate() + .alpha(showContractedChild ? 0f : 1f) + .setDuration(ANIMATION_DURATION_LENGTH) + .setInterpolator(mLinearInterpolator) + .withEndAction(new Runnable() { + @Override + public void run() { + mContractedChild.setLayerType(LAYER_TYPE_NONE, null); + mExpandedChild.setLayerType(LAYER_TYPE_NONE, null); + setLayerType(LAYER_TYPE_NONE, null); + mContractedChild.setVisibility(showContractedChild + ? View.VISIBLE + : View.INVISIBLE); + mExpandedChild.setVisibility(showContractedChild + ? View.INVISIBLE + : View.VISIBLE); + } + }); + } + + private boolean showContractedChild() { + return mActualHeight <= mSmallHeight || mExpandedChild == null; } public void notifyContentUpdated() { - selectLayout(); + selectLayout(false /* animate */, true /* force */); } public boolean isContentExpandable() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationScrimView.java new file mode 100644 index 0000000..440b2c1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationScrimView.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.statusbar; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.View; + +import com.android.keyguard.R; + +/** + * A view that can be used for both the dimmed and normal background of an notification. + */ +public class NotificationScrimView extends View { + + private Drawable mBackground; + private int mClipTopAmount; + private int mActualHeight; + + public NotificationScrimView(Context context, AttributeSet attrs) { + super(context, attrs); + mBackground = getResources().getDrawable(R.drawable.notification_scrim); + } + + @Override + protected void onDraw(Canvas canvas) { + draw(canvas, mBackground); + } + + private void draw(Canvas canvas, Drawable drawable) { + if (drawable != null) { + drawable.setBounds(0, mClipTopAmount, getWidth(), mActualHeight); + drawable.draw(canvas); + } + } + + @Override + protected boolean verifyDrawable(Drawable who) { + return super.verifyDrawable(who) || who == mBackground; + } + + public void setActualHeight(int actualHeight) { + mActualHeight = actualHeight; + invalidate(); + } + + public int getActualHeight() { + return mActualHeight; + } + + public void setClipTopAmount(int clipTopAmount) { + mClipTopAmount = clipTopAmount; + invalidate(); + } + + @Override + public boolean hasOverlappingRendering() { + + // Prevents this view from creating a layer when alpha is animating. + return false; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java index f80f0fd..650abaa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java @@ -121,4 +121,9 @@ public class SpeedBumpView extends ExpandableView { public void performAddAnimation(long delay) { performVisibilityAnimation(true); } + + @Override + public void setScrimAmount(float scrimAmount) { + // We don't need to scrim the speedbumps + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 97aa993..63698e4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -58,6 +58,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private ImageView mCameraImageView; private ImageView mPhoneImageView; private ImageView mLockIcon; + private View mIndicationText; private ActivityStarter mActivityStarter; private UnlockMethodCache mUnlockMethodCache; @@ -87,6 +88,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mCameraImageView = (ImageView) findViewById(R.id.camera_button); mPhoneImageView = (ImageView) findViewById(R.id.phone_button); mLockIcon = (ImageView) findViewById(R.id.lock_icon); + mIndicationText = findViewById(R.id.keyguard_indication_text); watchForCameraPolicyChanges(); watchForAccessibilityChanges(); updateCameraVisibility(); @@ -231,6 +233,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL return mLockIcon; } + public View getIndicationView() { + return mIndicationText; + } + @Override public void onMethodSecureChanged(boolean methodSecure) { updateTrust(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java index 6a83a5e..319096d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone; import android.content.res.Resources; import android.graphics.Path; +import android.view.animation.AccelerateInterpolator; import android.view.animation.PathInterpolator; import com.android.systemui.R; @@ -31,6 +32,10 @@ public class KeyguardClockPositionAlgorithm { 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_SCALE_FADE_START = 0.95f; + private static final float CLOCK_SCALE_FADE_END = 0.75f; + private static final float CLOCK_SCALE_FADE_END_NO_NOTIFS = 0.5f; + private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MIN = 1.4f; private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MAX = 3.2f; @@ -61,6 +66,8 @@ public class KeyguardClockPositionAlgorithm { sSlowDownInterpolator = new PathInterpolator(path); } + private AccelerateInterpolator mAccelerateInterpolator = new AccelerateInterpolator(); + /** * Refreshes the dimension values. */ @@ -87,18 +94,29 @@ public class KeyguardClockPositionAlgorithm { } public void run(Result result) { - int y = getClockY() - mKeyguardStatusHeight/2; + 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)); + result.clockScale = getClockScale(result.stackScrollerPadding, + result.clockY, + y + getClockNotificationsPadding() + mKeyguardStatusHeight); + result.clockAlpha = getClockAlpha(result.clockScale); + } + + private float getClockScale(int notificationPadding, int clockY, int startPadding) { + float scaleMultiplier = getNotificationAmountT() == 0 ? 6.0f : 5.0f; + float scaleEnd = clockY - mKeyguardStatusHeight * scaleMultiplier; + float distanceToScaleEnd = notificationPadding - scaleEnd; + float progress = distanceToScaleEnd / (startPadding - scaleEnd); + progress = Math.max(0.0f, Math.min(progress, 1.0f)); + progress = mAccelerateInterpolator.getInterpolation(progress); + return progress; } private int getClockNotificationsPadding() { @@ -144,11 +162,12 @@ public class KeyguardClockPositionAlgorithm { + 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; + private float getClockAlpha(float scale) { + float fadeEnd = getNotificationAmountT() == 0.0f + ? CLOCK_SCALE_FADE_END_NO_NOTIFS + : CLOCK_SCALE_FADE_END; + float alpha = (scale - fadeEnd) + / (CLOCK_SCALE_FADE_START - fadeEnd); return Math.max(0, Math.min(1, alpha)); } @@ -168,6 +187,11 @@ public class KeyguardClockPositionAlgorithm { public int clockY; /** + * The scale of the Clock + */ + public float clockScale; + + /** * The alpha value of the clock. */ public float clockAlpha; 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 dde95bf..a6ce5d5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -32,6 +32,7 @@ import android.view.accessibility.AccessibilityEvent; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.widget.LinearLayout; +import android.widget.TextView; import com.android.systemui.R; import com.android.systemui.statusbar.ExpandableView; @@ -48,6 +49,11 @@ public class NotificationPanelView extends PanelView implements View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener, KeyguardPageSwipeHelper.Callback { + // Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is + // changed. + private static final int CAP_HEIGHT = 1456; + private static final int FONT_HEIGHT = 2163; + private static final float LOCK_ICON_ACTIVE_SCALE = 1.2f; private KeyguardPageSwipeHelper mPageSwiper; @@ -56,7 +62,7 @@ public class NotificationPanelView extends PanelView implements private View mQsPanel; private View mKeyguardStatusView; private ObservableScrollView mScrollView; - private View mStackScrollerContainer; + private TextView mClockView; private NotificationStackScrollLayout mNotificationStackScroller; private int mNotificationTopPadding; @@ -105,9 +111,11 @@ public class NotificationPanelView extends PanelView implements new KeyguardClockPositionAlgorithm.Result(); private boolean mIsSwipedHorizontally; private boolean mIsExpanding; - private KeyguardBottomAreaView mKeyguardBottomArea; + private boolean mBlockTouches; private ArrayList<View> mSwipeTranslationViews = new ArrayList<>(); + private int mNotificationScrimWaitDistance; + private boolean mOnNotificationsOnDown; public NotificationPanelView(Context context, AttributeSet attrs) { super(context, attrs); @@ -135,9 +143,9 @@ public class NotificationPanelView extends PanelView implements mHeader.getBackgroundView().setOnClickListener(this); mHeader.setOverlayParent(this); 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); + mClockView = (TextView) findViewById(R.id.clock_view); mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view); mScrollView.setListener(this); mNotificationStackScroller = (NotificationStackScrollLayout) @@ -169,12 +177,19 @@ public class NotificationPanelView extends PanelView implements getResources().getDimensionPixelSize(R.dimen.header_notifications_collide_distance); mUnlockMoveDistance = getResources().getDimensionPixelOffset(R.dimen.unlock_move_distance); mClockPositionAlgorithm.loadDimens(getResources()); + mNotificationScrimWaitDistance = + getResources().getDimensionPixelSize(R.dimen.notification_scrim_wait_distance); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); + // Update Clock Pivot + mKeyguardStatusView.setPivotX(getWidth() / 2); + mKeyguardStatusView.setPivotY( + (FONT_HEIGHT - CAP_HEIGHT) / 2048f * mClockView.getTextSize()); + // Calculate quick setting heights. mQsMinExpansionHeight = mHeader.getCollapsedHeight() + mQsPeekHeight; mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getHeight(); @@ -197,7 +212,7 @@ public class NotificationPanelView extends PanelView implements * showing. */ private void positionClockAndNotifications() { - boolean animateClock = mNotificationStackScroller.isAddOrRemoveAnimationPending(); + boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending(); int stackScrollerPadding; if (mStatusBar.getBarState() != StatusBarState.KEYGUARD) { int bottom = mStackScrollerOverscrolling @@ -215,17 +230,17 @@ public class NotificationPanelView extends PanelView implements getHeight(), mKeyguardStatusView.getHeight()); mClockPositionAlgorithm.run(mClockPositionResult); - if (animateClock || mClockAnimator != null) { + if (animate || mClockAnimator != null) { startClockAnimation(mClockPositionResult.clockY); } else { mKeyguardStatusView.setY(mClockPositionResult.clockY); } - applyClockAlpha(mClockPositionResult.clockAlpha); + updateClock(mClockPositionResult.clockAlpha, mClockPositionResult.clockScale); stackScrollerPadding = mClockPositionResult.stackScrollerPadding; mTopPaddingAdjustment = mClockPositionResult.stackScrollerPaddingAdjustment; } mNotificationStackScroller.setIntrinsicPadding(stackScrollerPadding); - requestScrollerTopPaddingUpdate(animateClock); + requestScrollerTopPaddingUpdate(animate); } private void startClockAnimation(int y) { @@ -258,13 +273,10 @@ public class NotificationPanelView extends PanelView implements }); } - private void applyClockAlpha(float alpha) { - if (alpha != 1.0f) { - mKeyguardStatusView.setLayerType(LAYER_TYPE_HARDWARE, null); - } else { - mKeyguardStatusView.setLayerType(LAYER_TYPE_NONE, null); - } + private void updateClock(float alpha, float scale) { mKeyguardStatusView.setAlpha(alpha); + mKeyguardStatusView.setScaleX(scale); + mKeyguardStatusView.setScaleY(scale); } public void animateToFullShade() { @@ -344,6 +356,7 @@ public class NotificationPanelView extends PanelView implements mInitialTouchX = x; initVelocityTracker(); trackMovement(event); + mOnNotificationsOnDown = isOnNotifications(x, y); if (shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, 0)) { getParent().requestDisallowInterceptTouchEvent(true); } @@ -391,6 +404,8 @@ public class NotificationPanelView extends PanelView implements if (mQsTracking) { flingQsWithCurrentVelocity(); mQsTracking = false; + } else if (mQsFullyExpanded && mOnNotificationsOnDown) { + flingSettings(0 /* vel */, false /* expand */); } mIntercepting = false; break; @@ -398,6 +413,10 @@ public class NotificationPanelView extends PanelView implements return !mQsExpanded && super.onInterceptTouchEvent(event); } + private boolean isOnNotifications(float x, float y) { + return mNotificationStackScroller.getChildAtPosition(x, y) != null; + } + @Override public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { @@ -577,9 +596,17 @@ public class NotificationPanelView extends PanelView implements mHeader.setExpansion(height - mQsPeekHeight); setQsTranslation(height); requestScrollerTopPaddingUpdate(false /* animate */); + updateNotificationScrim(height); mStatusBar.userActivity(); } + private void updateNotificationScrim(float height) { + int startDistance = mQsMinExpansionHeight + mNotificationScrimWaitDistance; + float progress = (height - startDistance) / (mQsMaxExpansionHeight - startDistance); + progress = Math.max(0.0f, Math.min(progress, 1.0f)); + mNotificationStackScroller.setScrimAlpha(progress); + } + private void setQsTranslation(float height) { mQsContainer.setY(height - mQsContainer.getHeight()); } 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 1f3098d..12aa004 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -62,6 +62,7 @@ public abstract class PanelView extends FrameLayout { protected int mTouchSlop; protected boolean mHintAnimationRunning; private boolean mOverExpandedBeforeFling; + private float mOriginalIndicationY; private ValueAnimator mHeightAnimator; private ObjectAnimator mPeekAnimator; @@ -82,6 +83,7 @@ public abstract class PanelView extends FrameLayout { private Interpolator mLinearOutSlowInInterpolator; private Interpolator mBounceInterpolator; + protected KeyguardBottomAreaView mKeyguardBottomArea; protected void onExpandingFinished() { mBar.onExpandingFinished(); @@ -652,6 +654,22 @@ public abstract class PanelView extends FrameLayout { }); animator.start(); mHeightAnimator = animator; + mOriginalIndicationY = mKeyguardBottomArea.getIndicationView().getY(); + mKeyguardBottomArea.getIndicationView().animate() + .y(mOriginalIndicationY - mHintDistance) + .setDuration(250) + .setInterpolator(mLinearOutSlowInInterpolator) + .withEndAction(new Runnable() { + @Override + public void run() { + mKeyguardBottomArea.getIndicationView().animate() + .y(mOriginalIndicationY) + .setDuration(450) + .setInterpolator(mBounceInterpolator) + .start(); + } + }) + .start(); } /** 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 c11a9ac..00951b2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -35,6 +35,7 @@ import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.app.ActivityManager; import android.app.ActivityManagerNative; +import android.app.IActivityManager; import android.app.Notification; import android.app.PendingIntent; import android.app.StatusBarManager; @@ -64,6 +65,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings.Global; +import android.provider.Settings.SettingNotFoundException; import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.StatusBarNotification; import android.util.ArraySet; @@ -82,7 +84,6 @@ import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewPropertyAnimator; import android.view.ViewStub; -import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.animation.AccelerateInterpolator; import android.view.animation.Animation; @@ -109,7 +110,6 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.ExpandableNotificationRow; import com.android.systemui.statusbar.GestureRecorder; -import com.android.systemui.statusbar.InterceptedNotifications; import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.NotificationData; import com.android.systemui.statusbar.NotificationData.Entry; @@ -123,6 +123,7 @@ import com.android.systemui.statusbar.policy.BluetoothControllerImpl; import com.android.systemui.statusbar.policy.CastControllerImpl; import com.android.systemui.statusbar.policy.DateView; import com.android.systemui.statusbar.policy.HeadsUpNotificationView; +import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.statusbar.policy.LocationControllerImpl; import com.android.systemui.statusbar.policy.NetworkControllerImpl; @@ -211,6 +212,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, ZenModeController mZenModeController; CastControllerImpl mCastController; VolumeComponent mVolumeComponent; + KeyguardUserSwitcher mKeyguardUserSwitcher; int mNaturalBarHeight = -1; int mIconSize = -1; @@ -260,6 +262,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, boolean mLeaveOpenOnKeyguardHide; KeyguardIndicationController mKeyguardIndicationController; + private boolean mKeyguardFadingAway; + private long mKeyguardFadingAwayDelay; + private long mKeyguardFadingAwayDuration; + int mKeyguardMaxNotificationCount; View mDateTimeView; @@ -267,7 +273,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private TextView mCarrierLabel; private boolean mCarrierLabelVisible = false; private int mCarrierLabelHeight; - private TextView mEmergencyCallLabel; private int mStatusBarHeaderHeight; private boolean mShowCarrierInPanel = false; @@ -393,14 +398,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, }}; private Runnable mOnFlipRunnable; - private InterceptedNotifications mIntercepted; private VelocityTracker mSettingsTracker; private float mSettingsDownY; private boolean mSettingsStarted; private boolean mSettingsCancelled; private boolean mSettingsClosing; private boolean mVisible; + private boolean mWaitingForKeyguardExit; + private Interpolator mLinearOutSlowIn; private Interpolator mAlphaOut = new PathInterpolator(0f, 0.4f, 1f, 1f); private Interpolator mAlphaIn = new PathInterpolator(0f, 0f, 0.8f, 1f); @@ -502,19 +508,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, }; @Override - public void setZenMode(int mode) { - super.setZenMode(mode); - if (!isDeviceProvisioned()) return; - final boolean zen = mode != Settings.Global.ZEN_MODE_OFF; - if (!zen) { - mIntercepted.releaseIntercepted(); - } - if (mIconPolicy != null) { - mIconPolicy.setZenMode(zen); - } - } - - @Override protected void setShowLockscreenNotifications(boolean show) { super.setShowLockscreenNotifications(show); updateStackScrollerState(); @@ -525,7 +518,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)) .getDefaultDisplay(); updateDisplaySize(); - mIntercepted = new InterceptedNotifications(mContext, this); super.start(); // calls createAndAddWindows() addNavigationBar(); @@ -714,26 +706,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, final SignalClusterView signalCluster = (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster); + mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext, + (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), mHeader); mNetworkController.addSignalCluster(signalCluster); signalCluster.setNetworkController(mNetworkController); - final boolean isAPhone = mNetworkController.hasVoiceCallingFeature(); if (isAPhone) { - mEmergencyCallLabel = - (TextView) mStatusBarWindow.findViewById(R.id.emergency_calls_only); - // TODO: Uncomment when correctly positioned -// if (mEmergencyCallLabel != null) { -// mNetworkController.addEmergencyLabelView(mEmergencyCallLabel); -// mEmergencyCallLabel.setOnClickListener(new View.OnClickListener() { -// public void onClick(View v) { }}); -// mEmergencyCallLabel.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { -// @Override -// public void onLayoutChange(View v, int left, int top, int right, int bottom, -// int oldLeft, int oldTop, int oldRight, int oldBottom) { -// updateCarrierLabelVisibility(false); -// }}); -// } + mNetworkController.addEmergencyLabelView(mHeader); } mCarrierLabel = (TextView)mStatusBarWindow.findViewById(R.id.carrier_label); @@ -759,6 +739,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, // updateCarrierLabelVisibility(false); } + mBatteryController.setStatusBarHeaderView(mHeader); + // Set up the quick settings tile panel mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel); if (mQSPanel != null) { @@ -906,6 +888,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } }; + private View.OnLongClickListener mLockToAppClickListener = new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + toggleLockedApp(); + return true; + } + }; + private int mShowSearchHoldoff = 0; private Runnable mShowSearchPanel = new Runnable() { public void run() { @@ -949,6 +939,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener); mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener); + mNavigationBarView.getRecentsButton().setLongClickable(true); + mNavigationBarView.getRecentsButton().setOnLongClickListener(mLockToAppClickListener); mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener); updateSearchPanel(); } @@ -1064,18 +1056,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } @Override - public void addNotificationInternal(StatusBarNotification notification, RankingMap ranking) { + public void addNotification(StatusBarNotification notification, RankingMap ranking) { if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey()); - if (mZenMode != Global.ZEN_MODE_OFF && mIntercepted.tryIntercept(notification, ranking)) { - // Forward the ranking so we can sort the new notification. - mNotificationData.updateRanking(ranking); - return; - } - mIntercepted.remove(notification.getKey()); - displayNotification(notification, ranking); - } - - public void displayNotification(StatusBarNotification notification, RankingMap ranking) { if (mUseHeadsUp && shouldInterrupt(notification)) { if (DEBUG) Log.d(TAG, "launching notification in heads up mode"); Entry interruptionCandidate = new Entry(notification, null); @@ -1157,21 +1139,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } @Override - public void updateNotificationInternal(StatusBarNotification notification, RankingMap ranking) { - super.updateNotificationInternal(notification, ranking); - // if we're here, then the notification is already in the shade - mIntercepted.remove(notification.getKey()); - } - - @Override - protected void updateRankingInternal(RankingMap ranking) { + protected void updateNotificationRanking(RankingMap ranking) { mNotificationData.updateRanking(ranking); - mIntercepted.retryIntercepts(ranking); updateNotifications(); } @Override - public void removeNotificationInternal(String key, RankingMap ranking) { + public void removeNotification(String key, RankingMap ranking) { if (ENABLE_HEADS_UP && mHeadsUpNotificationView.getEntry() != null && key.equals(mHeadsUpNotificationView.getEntry().notification.getKey())) { mHeadsUpNotificationView.clear(); @@ -1194,7 +1168,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, animateCollapsePanels(); } } - mIntercepted.remove(key); setAreThereNotifications(); } @@ -1350,9 +1323,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, // in "public" mode (atop a secure keyguard), secret notifs are totally hidden continue; } - if (mIntercepted.isSyntheticEntry(ent)) { - continue; - } toShow.add(ent.icon); } @@ -1387,7 +1357,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mCarrierLabelHeight)); } - final boolean emergencyCallsShownElsewhere = mEmergencyCallLabel != null; + // Emergency calls only is shown in the expanded header now. + final boolean emergencyCallsShownElsewhere = true; final boolean makeVisible = !(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly()) && mStackScroller.getHeight() < (mNotificationPanel.getHeight() @@ -1465,7 +1436,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } private int adjustDisableFlags(int state) { - if (mExpandedVisible) { + if (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit) { state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS; state |= StatusBarManager.DISABLE_SYSTEM_INFO; } @@ -1513,19 +1484,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) { mSystemIconArea.animate().cancel(); if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) { - mSystemIconArea.animate() - .alpha(0f) - .withLayer() - .setDuration(160) - .setInterpolator(mAlphaIn) - .setListener(mMakeIconsInvisible); + animateStatusBarHide(mSystemIconArea); } else { - mSystemIconArea.setVisibility(View.VISIBLE); - mSystemIconArea.animate() - .alpha(1f) - .withLayer() - .setInterpolator(mAlphaOut) - .setDuration(320); + animateStatusBarShow(mSystemIconArea); } } @@ -1558,25 +1519,48 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (mTicking) { haltTicker(); } - - mNotificationIcons.animate() - .alpha(0f) - .withLayer() - .setDuration(160) - .setInterpolator(mAlphaIn) - .setListener(mMakeIconsInvisible) - .start(); + animateStatusBarHide(mNotificationIcons); } else { - mNotificationIcons.setVisibility(View.VISIBLE); - mNotificationIcons.animate() - .alpha(1f) - .withLayer() - .setInterpolator(mAlphaOut) - .setDuration(320); + animateStatusBarShow(mNotificationIcons); } } } + /** + * Animates {@code v}, a view that is part of the status bar, out. + */ + private void animateStatusBarHide(View v) { + v.animate() + .alpha(0f) + .withLayer() + .setDuration(160) + .setInterpolator(mAlphaIn) + .setStartDelay(0) + .setListener(mMakeIconsInvisible) + .start(); + } + + /** + * Animates {@code v}, a view that is part of the status bar, in. + */ + private void animateStatusBarShow(View v) { + v.setVisibility(View.VISIBLE); + v.animate() + .alpha(1f) + .withLayer() + .setInterpolator(mAlphaOut) + .setDuration(320) + .setStartDelay(0); + + // Synchronize the motion with the Keyguard fading if necessary. + if (mKeyguardFadingAway) { + v.animate() + .setDuration(mKeyguardFadingAwayDuration) + .setInterpolator(mLinearOutSlowIn) + .setStartDelay(mKeyguardFadingAwayDelay); + } + } + @Override protected BaseStatusBar.H createHandler() { return new PhoneStatusBar.H(); @@ -1678,6 +1662,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mStatusBarWindowManager.setStatusBarExpanded(true); visibilityChanged(true); + mWaitingForKeyguardExit = false; disable(mDisabledUnmodified); setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); } @@ -1718,7 +1703,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } if (mStatusBarWindow != null) { - // release focus immediately to kick off focus change transition mStatusBarWindowManager.setStatusBarFocusable(false); @@ -1872,8 +1856,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); - disable(mDisabledUnmodified); showBouncer(); + disable(mDisabledUnmodified); } public boolean interceptTouchEvent(MotionEvent event) { @@ -1960,6 +1944,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, Integer.toHexString(oldVal), Integer.toHexString(newVal), Integer.toHexString(diff))); if (diff != 0) { + // we never set the recents bit via this method, so save the prior state to prevent + // clobbering the bit below + final boolean wasRecentsVisible = (mSystemUiVisibility & View.RECENT_APPS_VISIBLE) > 0; + mSystemUiVisibility = newVal; // update low profile @@ -2014,6 +2002,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE; } + // restore the recents bit + if (wasRecentsVisible) { + mSystemUiVisibility |= View.RECENT_APPS_VISIBLE; + } + // send updated sysui visibility to window manager notifyUiVisibilityChanged(mSystemUiVisibility); } @@ -2578,6 +2571,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (mQSPanel != null) mQSPanel.updateResources(); loadDimens(); + mLinearOutSlowIn = AnimationUtils.loadInterpolator( + mContext, android.R.interpolator.linear_out_slow_in); } protected void loadDimens() { @@ -2905,6 +2900,27 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, updateKeyguardState(); } + /** + * Notifies the status bar the Keyguard is fading away with the specified timings. + * + * @param delay the animation delay in miliseconds + * @param fadeoutDuration the duration of the exit animation, in milliseconds + */ + public void setKeyguardFadingAway(long delay, long fadeoutDuration) { + mKeyguardFadingAway = true; + mKeyguardFadingAwayDelay = delay; + mKeyguardFadingAwayDuration = fadeoutDuration; + mWaitingForKeyguardExit = false; + disable(mDisabledUnmodified); + } + + /** + * Notifies that the Keyguard fading away animation is done. + */ + public void finishKeyguardFadingAway() { + mKeyguardFadingAway = false; + } + private void updatePublicMode() { setLockscreenPublicMode( (mStatusBarKeyguardViewManager.isShowing() || @@ -2917,9 +2933,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mKeyguardStatusView.setVisibility(View.VISIBLE); mKeyguardIndicationController.setVisible(true); mNotificationPanel.resetViews(); + mKeyguardUserSwitcher.setKeyguard(true); } else { mKeyguardStatusView.setVisibility(View.GONE); mKeyguardIndicationController.setVisible(false); + mKeyguardUserSwitcher.setKeyguard(false); } if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { mKeyguardBottomArea.setVisibility(View.VISIBLE); @@ -2979,6 +2997,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private void showBouncer() { if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { + mWaitingForKeyguardExit = true; mStatusBarKeyguardViewManager.dismiss(); } } @@ -3129,6 +3148,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mSystemIconArea.addView(mSystemIcons, 0); } + @Override + public void setBouncerShowing(boolean bouncerShowing) { + super.setBouncerShowing(bouncerShowing); + disable(mDisabledUnmodified); + } + public void onScreenTurnedOff() { mStackScroller.setAnimationsEnabled(false); } @@ -3137,6 +3162,28 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mStackScroller.setAnimationsEnabled(true); } + public void toggleLockedApp() { + Log.d(TAG, "Trying to toggle lock-to-app"); + try { + IActivityManager activityManager = ActivityManagerNative.getDefault(); + if (activityManager.isInLockTaskMode()) { + activityManager.stopLockTaskModeOnCurrent(); + } else { + try { + boolean lockToAppEnabled = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.LOCK_TO_APP_ENABLED) != 0; + if (lockToAppEnabled) { + activityManager.startLockTaskModeOnCurrent(); + } + } catch (SettingNotFoundException e) { + // No setting, not enabled. + } + } + } catch (RemoteException e) { + Log.d(TAG, "Unable to toggle Lock-to-app", e); + } + } + private final Runnable mUserActivity = new Runnable() { @Override public void run() { @@ -3145,4 +3192,41 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } } }; + + // Recents + + @Override + protected void showRecents(boolean triggeredFromAltTab) { + // Set the recents visibility flag + mSystemUiVisibility |= View.RECENT_APPS_VISIBLE; + notifyUiVisibilityChanged(mSystemUiVisibility); + super.showRecents(triggeredFromAltTab); + } + + @Override + protected void hideRecents(boolean triggeredFromAltTab) { + // Unset the recents visibility flag + mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE; + notifyUiVisibilityChanged(mSystemUiVisibility); + super.hideRecents(triggeredFromAltTab); + } + + @Override + protected void toggleRecents() { + // Toggle the recents visibility flag + mSystemUiVisibility ^= View.RECENT_APPS_VISIBLE; + notifyUiVisibilityChanged(mSystemUiVisibility); + super.toggleRecents(); + } + + @Override + public void onVisibilityChanged(boolean visible) { + // Update the recents visibility flag + if (visible) { + mSystemUiVisibility |= View.RECENT_APPS_VISIBLE; + } else { + mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE; + } + notifyUiVisibilityChanged(mSystemUiVisibility); + } } 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 7837769..fc10a08 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java @@ -26,6 +26,7 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; +import android.widget.TextView; import com.android.systemui.R; import com.android.systemui.qs.QSPanel; @@ -57,6 +58,12 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private View mSignalCluster; private View mSettingsButton; private View mBrightnessContainer; + private View mEmergencyCallsOnly; + private TextView mChargingInfo; + + private boolean mShowEmergencyCallsOnly; + private boolean mShowChargingInfo; + private boolean mKeyguardUserSwitcherShowing; private int mCollapsedHeight; private int mExpandedHeight; @@ -66,6 +73,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private int mNormalWidth; private int mPadding; private int mMultiUserExpandedMargin; + private int mSystemIconsSwitcherHiddenExpandedMargin; private ActivityStarter mActivityStarter; private BrightnessController mBrightnessController; @@ -93,6 +101,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mBrightnessController = new BrightnessController(getContext(), (ImageView) findViewById(R.id.brightness_icon), (ToggleSlider) findViewById(R.id.brightness_slider)); + mEmergencyCallsOnly = findViewById(R.id.header_emergency_calls_only); + mChargingInfo = (TextView) findViewById(R.id.header_charging_info); loadDimens(); updateVisibilities(); addOnLayoutChangeListener(new View.OnLayoutChangeListener() { @@ -117,7 +127,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mPadding = getResources().getDimensionPixelSize(R.dimen.notification_side_padding); mMultiUserExpandedMargin = getResources().getDimensionPixelSize(R.dimen.multi_user_switch_expanded_margin); - + mSystemIconsSwitcherHiddenExpandedMargin = getResources().getDimensionPixelSize( + R.dimen.system_icons_switcher_hidden_expanded_margin); } public void setActivityStarter(ActivityStarter activityStarter) { @@ -204,13 +215,40 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL if (mSignalCluster != null) { mSignalCluster.setVisibility(!mExpanded || mOverscrolled ? View.VISIBLE : View.GONE); } + mEmergencyCallsOnly.setVisibility(mExpanded && !mOverscrolled && mShowEmergencyCallsOnly + ? VISIBLE : GONE); + mChargingInfo.setVisibility(mExpanded && !mOverscrolled && mShowChargingInfo + && !mShowEmergencyCallsOnly ? VISIBLE : GONE); + mMultiUserSwitch.setVisibility(mExpanded || !mKeyguardUserSwitcherShowing + ? VISIBLE : GONE); } private void updateSystemIconsLayoutParams() { RelativeLayout.LayoutParams lp = (LayoutParams) mSystemIconsContainer.getLayoutParams(); - lp.addRule(RelativeLayout.START_OF, mExpanded - ? mSettingsButton.getId() - : mMultiUserSwitch.getId()); + boolean systemIconsAboveClock = mExpanded && !mOverscrolled + && mShowChargingInfo && !mShowEmergencyCallsOnly; + lp.setMarginEnd(0); + if (systemIconsAboveClock) { + lp.addRule(ALIGN_PARENT_START); + lp.removeRule(START_OF); + } else { + lp.addRule(RelativeLayout.START_OF, mExpanded + ? mSettingsButton.getId() + : mMultiUserSwitch.getId()); + lp.removeRule(ALIGN_PARENT_START); + if (mMultiUserSwitch.getVisibility() == GONE) { + lp.setMarginEnd(mSystemIconsSwitcherHiddenExpandedMargin); + } + } + mSystemIconsContainer.setLayoutParams(lp); + + RelativeLayout.LayoutParams clockLp = (LayoutParams) mDateTime.getLayoutParams(); + if (systemIconsAboveClock) { + clockLp.addRule(BELOW, mChargingInfo.getId()); + } else { + clockLp.addRule(BELOW, mEmergencyCallsOnly.getId()); + } + mDateTime.setLayoutParams(clockLp); } private void updateBrightnessControllerState() { @@ -338,4 +376,31 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL public boolean shouldDelayChildPressedState() { return true; } + + public void setShowEmergencyCallsOnly(boolean show) { + mShowEmergencyCallsOnly = show; + if (mExpanded) { + updateVisibilities(); + updateSystemIconsLayoutParams(); + } + } + + public void setShowChargingInfo(boolean showChargingInfo) { + mShowChargingInfo = showChargingInfo; + if (mExpanded) { + updateVisibilities(); + updateSystemIconsLayoutParams(); + } + } + + public void setChargingInfo(CharSequence chargingInfo) { + mChargingInfo.setText(chargingInfo); + } + + public void setKeyguardUserSwitcherShowing(boolean showing) { + // STOPSHIP: NOT CALLED PROPERLY WHEN GOING TO FULL SHADE AND RETURNING!?! + mKeyguardUserSwitcherShowing = showing; + updateVisibilities(); + updateSystemIconsLayoutParams(); + } } 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 09e4d94..a36f3d6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -190,19 +190,23 @@ public class StatusBarKeyguardViewManager { */ public void hide(long startTime, long fadeoutDuration) { mShowing = false; - mPhoneStatusBar.hideKeyguard(); - mStatusBarWindowManager.setKeyguardFadingAway(true); - mStatusBarWindowManager.setKeyguardShowing(false); + long uptimeMillis = SystemClock.uptimeMillis(); long delay = startTime - uptimeMillis; if (delay < 0) { delay = 0; } + + mPhoneStatusBar.setKeyguardFadingAway(delay, fadeoutDuration); + mPhoneStatusBar.hideKeyguard(); + mStatusBarWindowManager.setKeyguardFadingAway(true); + mStatusBarWindowManager.setKeyguardShowing(false); mBouncer.animateHide(delay, fadeoutDuration); mScrimController.animateKeyguardFadingOut(delay, fadeoutDuration, new Runnable() { @Override public void run() { mStatusBarWindowManager.setKeyguardFadingAway(false); + mPhoneStatusBar.finishKeyguardFadingAway(); } }); mViewMediatorCallback.keyguardGone(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java new file mode 100644 index 0000000..6f2642a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java @@ -0,0 +1,219 @@ +/* + * 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 com.android.systemui.R; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Shader; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.View; + +/** + * A view that displays a user image cropped to a circle with a frame. + */ +public class UserAvatarView extends View { + + private int mActiveFrameColor; + private int mFrameColor; + private float mFrameWidth; + private Bitmap mBitmap; + private Drawable mDrawable; + + private final Paint mFramePaint = new Paint(); + private final Paint mBitmapPaint = new Paint(); + private final Matrix mDrawMatrix = new Matrix(); + + private float mScale = 1; + + public UserAvatarView(Context context, AttributeSet attrs, + int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.UserAvatarView, defStyleAttr, defStyleRes); + final int N = a.getIndexCount(); + for (int i = 0; i < N; i++) { + int attr = a.getIndex(i); + switch (attr) { + case R.styleable.UserAvatarView_frameWidth: + setFrameWidth(a.getDimension(attr, 0)); + break; + case R.styleable.UserAvatarView_activeFrameColor: + setActiveFrameColor(a.getColor(attr, 0)); + break; + case R.styleable.UserAvatarView_frameColor: + setFrameColor(a.getColor(attr, 0)); + break; + } + } + a.recycle(); + + mFramePaint.setAntiAlias(true); + mFramePaint.setStyle(Paint.Style.STROKE); + mBitmapPaint.setAntiAlias(true); + } + + public UserAvatarView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public UserAvatarView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public UserAvatarView(Context context) { + this(context, null); + } + + public void setBitmap(Bitmap bitmap) { + setDrawable(null); + mBitmap = bitmap; + if (mBitmap != null) { + mBitmapPaint.setShader(new BitmapShader( + bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); + } else { + mBitmapPaint.setShader(null); + } + configureBounds(); + invalidate(); + } + + public void setFrameColor(int frameColor) { + mFrameColor = frameColor; + invalidate(); + } + + public void setActiveFrameColor(int activeFrameColor) { + mActiveFrameColor = activeFrameColor; + invalidate(); + } + + public void setFrameWidth(float frameWidth) { + mFrameWidth = frameWidth; + invalidate(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + configureBounds(); + } + + public void configureBounds() { + int vwidth = getWidth() - mPaddingLeft - mPaddingRight; + int vheight = getHeight() - mPaddingTop - mPaddingBottom; + + int dwidth; + int dheight; + if (mBitmap != null) { + dwidth = mBitmap.getWidth(); + dheight = mBitmap.getHeight(); + } else if (mDrawable != null) { + dwidth = mDrawable.getIntrinsicWidth(); + dheight = mDrawable.getIntrinsicHeight(); + mDrawable.setBounds(0, 0, dwidth, dheight); + vwidth -= 2 * (mFrameWidth - 1); + vheight -= 2 * (mFrameWidth - 1); + } else { + return; + } + + float scale; + float dx; + float dy; + + scale = Math.min((float) vwidth / (float) dwidth, + (float) vheight / (float) dheight); + + dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f); + dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f); + + mDrawMatrix.setScale(scale, scale); + mDrawMatrix.postTranslate(dx, dy); + mScale = scale; + } + + @Override + protected void onDraw(Canvas canvas) { + int frameColor = isActivated() ? mActiveFrameColor : mFrameColor; + float halfW = getWidth() / 2f; + float halfH = getHeight() / 2f; + float halfSW = Math.min(halfH, halfW); + if (mBitmap != null && mScale > 0) { + int saveCount = canvas.getSaveCount(); + canvas.save(); + canvas.translate(mPaddingLeft, mPaddingTop); + canvas.concat(mDrawMatrix); + float halfBW = mBitmap.getWidth() / 2f; + float halfBH = mBitmap.getHeight() / 2f; + float halfBSW = Math.min(halfBH, halfBW); + canvas.drawCircle(halfBW, halfBH, halfBSW - mFrameWidth / mScale + 1, mBitmapPaint); + canvas.restoreToCount(saveCount); + } else if (mDrawable != null && mScale > 0) { + int saveCount = canvas.getSaveCount(); + canvas.save(); + canvas.translate(mPaddingLeft, mPaddingTop); + canvas.translate(mFrameWidth - 1, mFrameWidth - 1); + canvas.concat(mDrawMatrix); + mDrawable.draw(canvas); + canvas.restoreToCount(saveCount); + } + if (frameColor != 0) { + mFramePaint.setColor(frameColor); + mFramePaint.setStrokeWidth(mFrameWidth); + canvas.drawCircle(halfW, halfH, halfSW - mFrameWidth / 2f, mFramePaint); + } + } + + public void setDrawable(Drawable d) { + if (mDrawable != null) { + mDrawable.setCallback(null); + unscheduleDrawable(mDrawable); + } + mDrawable = d; + if (d != null) { + d.setCallback(this); + if (d.isStateful()) { + d.setState(getDrawableState()); + } + d.setLayoutDirection(getLayoutDirection()); + configureBounds(); + } + if (d != null) { + mBitmap = null; + } + configureBounds(); + invalidate(); + } + + @Override + public void invalidateDrawable(Drawable dr) { + if (dr == mDrawable) { + invalidate(); + } else { + super.invalidateDrawable(dr); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java index 6db9bc3..4cf66a3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java @@ -16,26 +16,49 @@ package com.android.systemui.statusbar.policy; +import com.android.internal.app.IBatteryStats; +import com.android.systemui.R; +import com.android.systemui.statusbar.phone.StatusBarHeaderView; + import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.BatteryManager; +import android.os.BatteryStats; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.text.format.Formatter; +import android.util.Log; import java.util.ArrayList; public class BatteryController extends BroadcastReceiver { private static final String TAG = "StatusBar.BatteryController"; - private ArrayList<BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<BatteryStateChangeCallback>(); + private Context mContext; + private StatusBarHeaderView mStatusBarHeaderView; + private IBatteryStats mBatteryInfo; + + private int mLevel; + private boolean mPluggedIn; + private boolean mCharging; + private boolean mCharged; + + public interface BatteryStateChangeCallback { - public void onBatteryLevelChanged(int level, boolean pluggedIn); + public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging); } public BatteryController(Context context) { + mContext = context; + + mBatteryInfo = IBatteryStats.Stub.asInterface( + ServiceManager.getService(BatteryStats.SERVICE_NAME)); + IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_BATTERY_CHANGED); context.registerReceiver(this, filter); @@ -45,24 +68,59 @@ public class BatteryController extends BroadcastReceiver { mChangeCallbacks.add(cb); } + public void setStatusBarHeaderView(StatusBarHeaderView statusBarHeaderView) { + mStatusBarHeaderView = statusBarHeaderView; + updateStatusBarHeaderView(); + } + public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { - final int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); + mLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); + mPluggedIn = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0; + final int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN); + mCharged = status == BatteryManager.BATTERY_STATUS_FULL; + mCharging = mCharged || status == BatteryManager.BATTERY_STATUS_CHARGING; - boolean plugged = false; - switch (status) { - case BatteryManager.BATTERY_STATUS_CHARGING: - case BatteryManager.BATTERY_STATUS_FULL: - plugged = true; - break; + updateStatusBarHeaderView(); + for (BatteryStateChangeCallback cb : mChangeCallbacks) { + cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging); } + } + } - for (BatteryStateChangeCallback cb : mChangeCallbacks) { - cb.onBatteryLevelChanged(level, plugged); + private void updateStatusBarHeaderView() { + if (mStatusBarHeaderView != null) { + mStatusBarHeaderView.setShowChargingInfo(mPluggedIn); + mStatusBarHeaderView.setChargingInfo(computeChargingInfo()); + } + } + + private String computeChargingInfo() { + if (!mPluggedIn || !mCharged && !mCharging) { + return mContext.getResources().getString(R.string.expanded_header_battery_not_charging); + } + + if (mCharged) { + return mContext.getResources().getString(R.string.expanded_header_battery_charged); + } + + // Try fetching charging time from battery stats. + try { + long chargingTimeRemaining = mBatteryInfo.computeChargeTimeRemaining(); + if (chargingTimeRemaining > 0) { + String chargingTimeFormatted = + Formatter.formatShortElapsedTime(mContext, chargingTimeRemaining); + return mContext.getResources().getString( + R.string.expanded_header_battery_charging_with_time, chargingTimeFormatted); } + } catch (RemoteException e) { + Log.e(TAG, "Error calling IBatteryStats: ", e); } + + // Fall back to simple charging label. + return mContext.getResources().getString(R.string.expanded_header_battery_charging); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java index cadb44a..f978833 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java @@ -20,6 +20,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.text.format.DateFormat; import android.util.AttributeSet; import android.widget.TextView; @@ -29,8 +30,6 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; -import libcore.icu.ICU; - public class DateView extends TextView { private static final String TAG = "DateView"; @@ -87,7 +86,7 @@ public class DateView extends TextView { if (mDateFormat == null) { final String dateFormat = getContext().getString(R.string.system_ui_date_pattern); final Locale l = Locale.getDefault(); - final String fmt = ICU.getBestDateTimePattern(dateFormat, l.toString()); + final String fmt = DateFormat.getBestDateTimePattern(l, dateFormat); mDateFormat = new SimpleDateFormat(fmt, l); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java index 330b599..0134fe8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java @@ -63,6 +63,7 @@ public class KeyButtonView extends ImageView { // Just an old-fashioned ImageView performLongClick(); } + setPressed(false); } } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java new file mode 100644 index 0000000..c90750c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.statusbar.policy; + +import com.android.systemui.R; +import com.android.systemui.statusbar.phone.StatusBarHeaderView; +import com.android.systemui.statusbar.phone.UserAvatarView; + +import android.app.ActivityManagerNative; +import android.content.Context; +import android.content.pm.UserInfo; +import android.graphics.Bitmap; +import android.os.AsyncTask; +import android.os.RemoteException; +import android.os.UserManager; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewStub; +import android.view.WindowManagerGlobal; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; + +/** + * Manages the user switcher on the Keyguard. + */ +public class KeyguardUserSwitcher implements View.OnClickListener { + + private static final String TAG = "KeyguardUserSwitcher"; + + private final Context mContext; + private final ViewGroup mUserSwitcher; + private final UserManager mUserManager; + private final StatusBarHeaderView mHeader; + + public KeyguardUserSwitcher(Context context, ViewStub userSwitcher, + StatusBarHeaderView header) { + mContext = context; + if (context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher)) { + mUserSwitcher = (ViewGroup) userSwitcher.inflate(); + mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + mHeader = header; + refresh(); + } else { + mUserSwitcher = null; + mUserManager = null; + mHeader = null; + } + } + + public void setKeyguard(boolean keyguard) { + if (mUserSwitcher != null) { + // TODO: Cache showUserSwitcherOnKeyguard(). + if (keyguard && showUserSwitcherOnKeyguard()) { + show(); + refresh(); + } else { + hide(); + } + } + } + + /** + * @return true if the user switcher should be shown on the lock screen. + * @see android.os.UserManager#isUserSwitcherEnabled() + */ + private boolean showUserSwitcherOnKeyguard() { + // TODO: Set isEdu. The edu provisioning process can add settings to Settings.Global. + boolean isEdu = false; + if (isEdu) { + return true; + } + List<UserInfo> users = mUserManager.getUsers(true /* excludeDying */); + int N = users.size(); + int switchableUsers = 0; + for (int i = 0; i < N; i++) { + if (users.get(i).supportsSwitchTo()) { + switchableUsers++; + } + } + return switchableUsers > 1; + } + + public void show() { + if (mUserSwitcher != null) { + // TODO: animate + mUserSwitcher.setVisibility(View.VISIBLE); + mHeader.setKeyguardUserSwitcherShowing(true); + } + } + + private void hide() { + if (mUserSwitcher != null) { + // TODO: animate + mUserSwitcher.setVisibility(View.GONE); + mHeader.setKeyguardUserSwitcherShowing(false); + } + } + + private void refresh() { + if (mUserSwitcher != null) { + new AsyncTask<Void, Void, ArrayList<UserData>>() { + @Override + protected ArrayList<UserData> doInBackground(Void... params) { + return loadUsers(); + } + + @Override + protected void onPostExecute(ArrayList<UserData> userInfos) { + bind(userInfos); + } + }.execute((Void[]) null); + } + } + + private void bind(ArrayList<UserData> userList) { + mUserSwitcher.removeAllViews(); + int N = userList.size(); + for (int i = 0; i < N; i++) { + mUserSwitcher.addView(inflateUser(userList.get(i))); + } + // TODO: add Guest + // TODO: add (+) button + } + + private View inflateUser(UserData user) { + View v = LayoutInflater.from(mUserSwitcher.getContext()).inflate( + R.layout.keyguard_user_switcher_item, mUserSwitcher, false); + TextView name = (TextView) v.findViewById(R.id.name); + UserAvatarView picture = (UserAvatarView) v.findViewById(R.id.picture); + name.setText(user.userInfo.name); + picture.setActivated(user.isCurrent); + if (user.userInfo.isGuest()) { + picture.setDrawable(mContext.getResources().getDrawable(R.drawable.ic_account_circle)); + } else { + picture.setBitmap(user.userIcon); + } + v.setOnClickListener(this); + v.setTag(user.userInfo); + // TODO: mark which user is current for accessibility. + return v; + } + + @Override + public void onClick(View v) { + switchUser(((UserInfo)v.getTag()).id); + } + + // TODO: Factor out logic below and share with QS implementation. + + private ArrayList<UserData> loadUsers() { + ArrayList<UserInfo> users = (ArrayList<UserInfo>) mUserManager + .getUsers(true /* excludeDying */); + int N = users.size(); + ArrayList<UserData> result = new ArrayList<>(N); + int currentUser = -1; + try { + currentUser = ActivityManagerNative.getDefault().getCurrentUser().id; + } catch (RemoteException e) { + Log.e(TAG, "Couln't get current user.", e); + } + for (int i = 0; i < N; i++) { + UserInfo user = users.get(i); + if (user.supportsSwitchTo()) { + boolean isCurrent = user.id == currentUser; + result.add(new UserData(user, mUserManager.getUserIcon(user.id), isCurrent)); + } + } + return result; + } + + private void switchUser(int userId) { + try { + WindowManagerGlobal.getWindowManagerService().lockNow(null); + ActivityManagerNative.getDefault().switchUser(userId); + } catch (RemoteException e) { + Log.e(TAG, "Couldn't switch user.", e); + } + } + + private static class UserData { + final UserInfo userInfo; + final Bitmap userIcon; + final boolean isCurrent; + + UserData(UserInfo userInfo, Bitmap userIcon, boolean isCurrent) { + this.userInfo = userInfo; + this.userIcon = userIcon; + this.isCurrent = isCurrent; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 254a0e8..4e54e41 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -47,6 +47,7 @@ import com.android.internal.telephony.cdma.EriInfo; import com.android.internal.util.AsyncChannel; import com.android.systemui.DemoMode; import com.android.systemui.R; +import com.android.systemui.statusbar.phone.StatusBarHeaderView; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -144,7 +145,7 @@ public class NetworkControllerImpl extends BroadcastReceiver ArrayList<TextView> mCombinedLabelViews = new ArrayList<TextView>(); ArrayList<TextView> mMobileLabelViews = new ArrayList<TextView>(); ArrayList<TextView> mWifiLabelViews = new ArrayList<TextView>(); - ArrayList<TextView> mEmergencyLabelViews = new ArrayList<TextView>(); + ArrayList<StatusBarHeaderView> mEmergencyViews = new ArrayList<>(); ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>(); ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks = new ArrayList<NetworkSignalChangedCallback>(); @@ -262,8 +263,8 @@ public class NetworkControllerImpl extends BroadcastReceiver mWifiLabelViews.add(v); } - public void addEmergencyLabelView(TextView v) { - mEmergencyLabelViews.add(v); + public void addEmergencyLabelView(StatusBarHeaderView v) { + mEmergencyViews.add(v); } public void addSignalCluster(SignalCluster cluster) { @@ -1254,15 +1255,10 @@ public class NetworkControllerImpl extends BroadcastReceiver } // e-call label - N = mEmergencyLabelViews.size(); + N = mEmergencyViews.size(); for (int i=0; i<N; i++) { - TextView v = mEmergencyLabelViews.get(i); - if (!emergencyOnly) { - v.setVisibility(View.GONE); - } else { - v.setText(mobileLabel); // comes from the telephony stack - v.setVisibility(View.VISIBLE); - } + StatusBarHeaderView v = mEmergencyViews.get(i); + v.setShowEmergencyCallsOnly(emergencyOnly); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java index 6d92b05..fcc951e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java @@ -32,6 +32,7 @@ public class AmbientState { private float mOverScrollTopAmount; private float mOverScrollBottomAmount; private int mSpeedBumpIndex = -1; + private float mScrimAmount; public int getScrollY() { return mScrollY; @@ -85,6 +86,14 @@ public class AmbientState { } } + public void setScrimAmount(float scrimAmount) { + mScrimAmount = scrimAmount; + } + + public float getScrimAmount() { + return mScrimAmount; + } + public float getOverScrollAmount(boolean top) { return top ? mOverScrollTopAmount : mOverScrollBottomAmount; } 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 4e1b686..f6e9aef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -541,8 +541,9 @@ public class NotificationStackScrollLayout extends ViewGroup if (slidingChild.getVisibility() == GONE) { continue; } - float top = slidingChild.getTranslationY(); - float bottom = top + slidingChild.getActualHeight(); + float childTop = slidingChild.getTranslationY(); + float top = childTop + slidingChild.getClipTopAmount(); + float bottom = childTop + slidingChild.getActualHeight(); int left = slidingChild.getLeft(); int right = slidingChild.getRight(); @@ -762,11 +763,12 @@ public class NotificationStackScrollLayout extends ViewGroup } } } - - mActivePointerId = INVALID_POINTER; - endDrag(); } + + mActivePointerId = INVALID_POINTER; + endDrag(); } + break; case MotionEvent.ACTION_CANCEL: if (mIsBeingDragged && getChildCount() > 0) { @@ -968,7 +970,7 @@ public class NotificationStackScrollLayout extends ViewGroup * @param animate Should an animation be performed. */ public void setOverScrolledPixels(float numPixels, boolean onTop, boolean animate) { - setOverScrollAmount(numPixels * getRubberBandFactor(), onTop, animate, true); + setOverScrollAmount(numPixels * getRubberBandFactor(onTop), onTop, animate, true); } /** @@ -1004,7 +1006,7 @@ public class NotificationStackScrollLayout extends ViewGroup if (animate) { mStateAnimator.animateOverScrollToAmount(amount, onTop); } else { - setOverScrolledPixels(amount / getRubberBandFactor(), onTop); + setOverScrolledPixels(amount / getRubberBandFactor(onTop), onTop); mAmbientState.setOverScrollAmount(amount, onTop); if (onTop) { notifyOverscrollTopListener(amount); @@ -1226,13 +1228,14 @@ public class NotificationStackScrollLayout extends ViewGroup mOwnScrollY -= (int) topAmount; mDontReportNextOverScroll = true; setOverScrollAmount(0, true, false); - mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor() + mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor(true /* onTop */) * mOverflingDistance + topAmount; } else if (velocityY > 0 && bottomAmount > 0) { mOwnScrollY += bottomAmount; setOverScrollAmount(0, false, false); - mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor() - * mOverflingDistance + bottomAmount; + mMaxOverScroll = Math.abs(velocityY) / 1000f + * getRubberBandFactor(false /* onTop */) * mOverflingDistance + + bottomAmount; } else { // it will be set once we reach the boundary mMaxOverScroll = 0.0f; @@ -1274,7 +1277,10 @@ public class NotificationStackScrollLayout extends ViewGroup return Math.max(desiredPadding, mIntrinsicPadding); } - private float getRubberBandFactor() { + private float getRubberBandFactor(boolean onTop) { + if (!onTop) { + return RUBBER_BAND_FACTOR_NORMAL; + } if (mExpandedInThisMotion) { return RUBBER_BAND_FACTOR_AFTER_EXPAND; } else if (mIsExpansionChanging) { @@ -1840,6 +1846,11 @@ public class NotificationStackScrollLayout extends ViewGroup return true; } + public void setScrimAlpha(float progress) { + mAmbientState.setScrimAmount(progress); + requestChildrenUpdate(); + } + /** * A listener that is notified when some child locations might have changed. */ 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 cbad9dc..9a4b798 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java @@ -154,6 +154,17 @@ public class StackScrollAlgorithm { handleDraggedViews(ambientState, resultState, algorithmState); updateDimmedActivated(ambientState, resultState, algorithmState); updateClipping(resultState, algorithmState); + updateScrimAmount(resultState, algorithmState, ambientState.getScrimAmount()); + } + + private void updateScrimAmount(StackScrollState resultState, + StackScrollAlgorithmState algorithmState, float scrimAmount) { + int childCount = algorithmState.visibleChildren.size(); + for (int i = 0; i < childCount; i++) { + View child = algorithmState.visibleChildren.get(i); + StackScrollState.ViewState childViewState = resultState.getViewStateForView(child); + childViewState.scrimAmount = scrimAmount; + } } private void updateClipping(StackScrollState resultState, @@ -587,6 +598,7 @@ public class StackScrollAlgorithm { algorithmState.itemsInTopStack += algorithmState.partialInTop; newSize = Math.max(mCollapsedSize, newSize); if (i == 0) { + algorithmState.itemsInTopStack = 1.0f; childViewState.height = (int) newSize; } algorithmState.lastTopStackIndex = i; @@ -617,6 +629,20 @@ public class StackScrollAlgorithm { if (i < algorithmState.itemsInTopStack) { float stackIndex = algorithmState.itemsInTopStack - i; stackIndex = Math.min(stackIndex, MAX_ITEMS_IN_TOP_STACK + 2); + if (i == 0 && algorithmState.itemsInTopStack < 2.0f) { + + // We only have the top item and an additional item in the top stack, + // Interpolate the index from 0 to 2 while the second item is + // translating in. + stackIndex -= 1.0f; + if (algorithmState.scrollY > mCollapsedSize) { + + // Since there is a shadow treshhold, we cant just interpolate from 0 to + // 2 but we interpolate from 0.1f to 2.0f when scrolled in. The jump in + // height will not be noticable since we have padding in between. + stackIndex = 0.1f + stackIndex * 1.9f; + } + } childViewState.zTranslation = mZBasicHeight + stackIndex * mZDistanceBetweenElements; } else if (i > (childCount - 1 - algorithmState.itemsInBottomStack)) { 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 1ad4acc..02f2cd6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java @@ -148,6 +148,9 @@ public class StackScrollState { // apply dimming child.setDimmed(state.dimmed, false /* animate */); + // apply scrimming + child.setScrimAmount(state.scrimAmount); + float oldClipTopAmount = child.getClipTopAmount(); if (oldClipTopAmount != state.clipTopAmount) { child.setClipTopAmount(state.clipTopAmount); @@ -223,6 +226,12 @@ public class StackScrollState { boolean dimmed; /** + * A value between 0 and 1 indicating how much the view should be scrimmed. + * 1 means that the notifications will be darkened as much as possible. + */ + float scrimAmount; + + /** * The amount which the view should be clipped from the top. This is calculated to * perceive consistent shadows. */ 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 225398a..0006dad 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java @@ -176,6 +176,9 @@ public class StackStateAnimator { // start dimmed animation child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed); + // apply scrimming + child.setScrimAmount(viewState.scrimAmount); + if (wasAdded) { child.performAddAnimation(delay); } 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 9260aac..e354166 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java @@ -47,27 +47,15 @@ public class TvStatusBar extends BaseStatusBar { } @Override - public void addNotification(StatusBarNotification notification) { + public void addNotification(StatusBarNotification notification, RankingMap ranking) { } @Override - public void addNotificationInternal(StatusBarNotification notification, RankingMap ranking) { + protected void updateNotificationRanking(RankingMap ranking) { } @Override - protected void updateRankingInternal(RankingMap ranking) { - } - - @Override - public void updateNotification(StatusBarNotification notification) { - } - - @Override - public void removeNotificationInternal(String key, RankingMap ranking) { - } - - @Override - public void removeNotification(String key) { + public void removeNotification(String key, RankingMap ranking) { } @Override |