diff options
23 files changed, 599 insertions, 150 deletions
diff --git a/packages/SystemUI/res/anim/car_user_switcher_close_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_close_animation.xml new file mode 100644 index 000000000000..ed637a7adcbf --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_close_animation.xml @@ -0,0 +1,20 @@ +<!-- Copyright (C) 2017 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. +--> +<animator xmlns:android="http://schemas.android.com/apk/res/android" + android:duration="133" + android:valueType="intType" + android:valueFrom="@dimen/car_user_switcher_container_height" + android:valueTo="0" + android:interpolator="@android:interpolator/fast_out_slow_in" /> diff --git a/packages/SystemUI/res/anim/car_user_switcher_close_icon_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_close_icon_animation.xml new file mode 100644 index 000000000000..227c981cb72a --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_close_icon_animation.xml @@ -0,0 +1,24 @@ +<!-- Copyright (C) 2017 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"> + + <objectAnimator + android:duration="167" + android:propertyName="rotation" + android:valueType="floatType" + android:valueFrom="180" + android:valueTo="0" + android:interpolator="@android:interpolator/fast_out_slow_in" /> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/anim/car_user_switcher_close_name_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_close_name_animation.xml new file mode 100644 index 000000000000..5901ff41735c --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_close_name_animation.xml @@ -0,0 +1,23 @@ +<!-- Copyright (C) 2017 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"> + + <objectAnimator + android:duration="83" + android:propertyName="alpha" + android:valueType="floatType" + android:valueFrom="0" + android:valueTo="1" /> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/anim/car_user_switcher_close_pages_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_close_pages_animation.xml new file mode 100644 index 000000000000..41cbe4b104c3 --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_close_pages_animation.xml @@ -0,0 +1,23 @@ +<!-- Copyright (C) 2017 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"> + + <objectAnimator + android:duration="83" + android:propertyName="alpha" + android:valueType="floatType" + android:valueFrom="1" + android:valueTo="0" /> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/anim/car_user_switcher_close_pod_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_close_pod_animation.xml new file mode 100644 index 000000000000..341e7e0cdfe9 --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_close_pod_animation.xml @@ -0,0 +1,24 @@ +<!-- Copyright (C) 2017 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:ordering="together" > + + <objectAnimator + android:duration="50" + android:propertyName="alpha" + android:valueType="floatType" + android:valueFrom="1" + android:valueTo="0" /> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/anim/car_user_switcher_open_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_open_animation.xml new file mode 100644 index 000000000000..6ae74131584d --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_open_animation.xml @@ -0,0 +1,20 @@ +<!-- Copyright (C) 2017 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. +--> +<animator xmlns:android="http://schemas.android.com/apk/res/android" + android:duration="200" + android:valueType="intType" + android:valueFrom="0" + android:valueTo="@dimen/car_user_switcher_container_height" + android:interpolator="@android:interpolator/fast_out_slow_in" /> diff --git a/packages/SystemUI/res/anim/car_user_switcher_open_icon_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_open_icon_animation.xml new file mode 100644 index 000000000000..06ac9e359b57 --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_open_icon_animation.xml @@ -0,0 +1,24 @@ +<!-- Copyright (C) 2017 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"> + + <objectAnimator + android:duration="167" + android:propertyName="rotation" + android:valueType="floatType" + android:valueFrom="0" + android:valueTo="180" + android:interpolator="@android:interpolator/fast_out_slow_in" /> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/anim/car_user_switcher_open_name_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_open_name_animation.xml new file mode 100644 index 000000000000..4baefb83a4ef --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_open_name_animation.xml @@ -0,0 +1,24 @@ +<!-- Copyright (C) 2017 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"> + + <objectAnimator + android:duration="83" + android:startOffset="83" + android:propertyName="alpha" + android:valueType="floatType" + android:valueFrom="1" + android:valueTo="0" /> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/anim/car_user_switcher_open_pages_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_open_pages_animation.xml new file mode 100644 index 000000000000..2d0deb95da59 --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_open_pages_animation.xml @@ -0,0 +1,24 @@ +<!-- Copyright (C) 2017 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"> + + <objectAnimator + android:duration="83" + android:startOffset="83" + android:propertyName="alpha" + android:valueType="floatType" + android:valueFrom="0" + android:valueTo="1" /> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/anim/car_user_switcher_open_pod_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_open_pod_animation.xml new file mode 100644 index 000000000000..3315220a60ef --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_open_pod_animation.xml @@ -0,0 +1,33 @@ +<!-- Copyright (C) 2017 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:ordering="together" > + + <objectAnimator + android:duration="167" + android:startOffset="67" + android:propertyName="translationY" + android:valueType="floatType" + android:valueFrom="@dimen/car_user_switcher_container_anim_height" + android:valueTo="0" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="83" + android:startOffset="117" + android:propertyName="alpha" + android:valueType="floatType" + android:valueFrom="0" + android:valueTo="1" /> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/car_ic_arrow.xml b/packages/SystemUI/res/drawable/car_ic_arrow.xml index 2c5ad27fe292..d400ed8c7707 100644 --- a/packages/SystemUI/res/drawable/car_ic_arrow.xml +++ b/packages/SystemUI/res/drawable/car_ic_arrow.xml @@ -1,5 +1,5 @@ <!-- - ~ Copyright (C) 2015 The Android Open Source Project + ~ Copyright (C) 2017 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. diff --git a/packages/SystemUI/res/drawable/car_ic_arrow_drop_up.xml b/packages/SystemUI/res/drawable/car_ic_arrow_drop_up.xml new file mode 100644 index 000000000000..33a512e31675 --- /dev/null +++ b/packages/SystemUI/res/drawable/car_ic_arrow_drop_up.xml @@ -0,0 +1,24 @@ +<!-- + ~ Copyright (C) 2015 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" + android:width="48.0dp" + android:height="48.0dp" + android:viewportWidth="48.0" + android:viewportHeight="48.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M14 28l10-10 10 10z"/> +</vector> diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml index 2f16516a6fea..0ee40d7ae47b 100644 --- a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml +++ b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml @@ -15,27 +15,40 @@ limitations under the License. --> -<LinearLayout +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" + android:clipChildren="false" + android:alpha="0" android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="center" > + android:layout_height="@dimen/car_fullscreen_user_pod_height" + android:layout_gravity="center_horizontal|bottom" > <ImageView android:id="@+id/user_avatar" - android:layout_gravity="center" + android:layout_centerHorizontal="true" + android:layout_marginTop="@dimen/car_fullscreen_user_pod_margin_image_top" android:layout_width="@dimen/car_fullscreen_user_pod_image_avatar_width" - android:layout_height="@dimen/car_fullscreen_user_pod_image_avatar_height" /> + android:layout_height="@dimen/car_fullscreen_user_pod_image_avatar_height" + android:layout_above="@id/user_name" /> <TextView android:id="@+id/user_name" android:layout_width="@dimen/car_fullscreen_user_pod_width" android:layout_height="wrap_content" android:layout_marginTop="@dimen/car_fullscreen_user_pod_margin_name_top" android:layout_marginBottom="@dimen/car_fullscreen_user_pod_margin_name_bottom" - android:textSize="@dimen/car_fullscreen_user_pod_text_size" + android:textSize="@dimen/car_fullscreen_user_pod_name_text_size" android:textColor="@color/qs_user_detail_name" android:ellipsize="end" android:singleLine="true" android:gravity="center_horizontal" - android:layout_gravity="center_horizontal" /> -</LinearLayout> + android:layout_above="@id/device_name" /> + + <TextView android:id="@+id/device_name" + android:layout_width="@dimen/car_fullscreen_user_pod_width" + android:layout_height="wrap_content" + android:textSize="@dimen/car_fullscreen_user_pod_device_text_size" + android:textColor="@color/qs_user_detail_name" + android:ellipsize="end" + android:singleLine="true" + android:gravity="center_horizontal" + android:layout_alignParentBottom="true" /> +</RelativeLayout> diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml b/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml index 99d010f2ac2b..d666a203298f 100644 --- a/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml +++ b/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml @@ -16,10 +16,10 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:clipChildren="false" android:layout_width="match_parent" android:layout_height="wrap_content" - android:gravity="center" - android:layout_gravity="center" > + android:gravity="center" > <!-- car_fullscreen_user_pods will be dynamically added here. --> </LinearLayout> diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml index 257e2814bb65..478b65642689 100644 --- a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml +++ b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml @@ -54,13 +54,13 @@ android:layout_height="wrap_content" android:layout_marginLeft="@dimen/car_margin" android:layout_marginRight="@dimen/car_margin" + android:layout_marginBottom="@dimen/car_user_grid_margin_bottom" android:layout_centerInParent="true" /> <com.android.systemui.statusbar.car.PageIndicator android:id="@+id/user_switcher_page_indicator" android:layout_width="match_parent" android:layout_height="@dimen/car_page_indicator_dot_diameter" - android:layout_marginTop="@dimen/car_page_indicator_margin_top" android:layout_below="@+id/user_grid" /> <Button diff --git a/packages/SystemUI/res/layout/car_qs_footer.xml b/packages/SystemUI/res/layout/car_qs_footer.xml index 044090be9f5d..3afd4ea33039 100644 --- a/packages/SystemUI/res/layout/car_qs_footer.xml +++ b/packages/SystemUI/res/layout/car_qs_footer.xml @@ -35,7 +35,6 @@ android:layout_centerVertical="true" android:layout_width="@dimen/car_qs_footer_icon_width" android:layout_height="@dimen/car_qs_footer_icon_height" - android:layout_marginRight="@dimen/car_qs_footer_user_switch_margin_right" android:background="@drawable/ripple_drawable" android:focusable="true"> @@ -47,6 +46,18 @@ android:scaleType="fitCenter"/> </com.android.systemui.statusbar.phone.MultiUserSwitch> + <ImageView + android:id="@+id/user_switch_expand_icon" + android:layout_height="match_parent" + android:layout_width="@dimen/car_qs_footer_user_switch_icon_width" + android:layout_centerVertical="true" + android:layout_toEndOf="@+id/multi_user_switch" + android:layout_marginLeft="@dimen/car_qs_footer_user_switch_icon_margin" + android:layout_marginRight="@dimen/car_qs_footer_user_switch_icon_margin" + android:src="@drawable/car_ic_arrow_drop_up" + android:scaleType="fitCenter"> + </ImageView> + <TextView android:id="@+id/user_name" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -54,7 +65,7 @@ android:textColor="@color/car_qs_footer_user_name_color" android:gravity="start|center_vertical" android:layout_centerVertical="true" - android:layout_toEndOf="@id/multi_user_switch" /> + android:layout_toEndOf="@id/user_switch_expand_icon" /> <com.android.systemui.statusbar.phone.SettingsButton android:id="@+id/settings_button" diff --git a/packages/SystemUI/res/layout/car_qs_panel.xml b/packages/SystemUI/res/layout/car_qs_panel.xml index 4cb0fd5fecfb..7844cac43f9a 100644 --- a/packages/SystemUI/res/layout/car_qs_panel.xml +++ b/packages/SystemUI/res/layout/car_qs_panel.xml @@ -16,6 +16,7 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/quick_settings_container" + android:clipChildren="false" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/car_qs_background_primary" @@ -26,10 +27,32 @@ <include layout="@layout/car_status_bar_header"/> <include layout="@layout/car_qs_footer"/> - <com.android.systemui.statusbar.car.UserGridView - android:id="@+id/user_grid" + <RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/user_switcher_container" + android:clipChildren="false" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="@dimen/car_margin" - android:layout_marginRight="@dimen/car_margin" /> + android:layout_height="@dimen/car_user_switcher_container_height" + android:layout_gravity="center_horizontal" > + + <com.android.systemui.statusbar.car.UserGridView + android:id="@+id/user_grid" + android:clipChildren="false" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="@dimen/car_margin" + android:layout_marginRight="@dimen/car_margin" + android:layout_marginBottom="@dimen/car_user_grid_margin_bottom" + android:layout_above="@id/user_switcher_page_indicator" /> + + <com.android.systemui.statusbar.car.PageIndicator + android:id="@+id/user_switcher_page_indicator" + android:layout_width="match_parent" + android:layout_height="@dimen/car_page_indicator_dot_diameter" + android:layout_marginBottom="@dimen/car_page_indicator_margin_bottom" + android:alpha="0" + android:layout_alignParentBottom="true" /> + + </RelativeLayout> + </LinearLayout> diff --git a/packages/SystemUI/res/values/dimens_car.xml b/packages/SystemUI/res/values/dimens_car.xml index 8853587dba47..f3c9f89bad41 100644 --- a/packages/SystemUI/res/values/dimens_car.xml +++ b/packages/SystemUI/res/values/dimens_car.xml @@ -18,20 +18,23 @@ <resources> <dimen name="car_margin">148dp</dimen> + <dimen name="car_fullscreen_user_pod_margin_image_top">24dp</dimen> <dimen name="car_fullscreen_user_pod_margin_name_top">24dp</dimen> - <dimen name="car_fullscreen_user_pod_margin_name_bottom">64dp</dimen> + <dimen name="car_fullscreen_user_pod_margin_name_bottom">20dp</dimen> <dimen name="car_fullscreen_user_pod_margin_between">24dp</dimen> <dimen name="car_fullscreen_user_pod_icon_text_size">96dp</dimen> <dimen name="car_fullscreen_user_pod_image_avatar_width">192dp</dimen> <dimen name="car_fullscreen_user_pod_image_avatar_height">192dp</dimen> <dimen name="car_fullscreen_user_pod_width">264dp</dimen> - <dimen name="car_fullscreen_user_pod_text_size">40sp</dimen> <!-- B1 --> + <dimen name="car_fullscreen_user_pod_height">356dp</dimen> + <dimen name="car_fullscreen_user_pod_name_text_size">40sp</dimen> <!-- B1 --> + <dimen name="car_fullscreen_user_pod_device_text_size">@dimen/car_body2_size</dimen> <dimen name="car_navigation_button_width">64dp</dimen> <dimen name="car_navigation_bar_width">760dp</dimen> <dimen name="car_page_indicator_dot_diameter">12dp</dimen> - <dimen name="car_page_indicator_margin_top">32dp</dimen> + <dimen name="car_page_indicator_margin_bottom">24dp</dimen> <dimen name="car_user_switcher_progress_bar_height">6dp</dimen> <dimen name="car_user_switcher_progress_bar_margin_top">@dimen/status_bar_height</dimen> @@ -47,8 +50,14 @@ <dimen name="car_qs_footer_padding_start">46dp</dimen> <dimen name="car_qs_footer_icon_width">56dp</dimen> <dimen name="car_qs_footer_icon_height">56dp</dimen> - <dimen name="car_qs_footer_user_switch_margin_right">46dp</dimen> + <dimen name="car_qs_footer_user_switch_icon_margin">5dp</dimen> + <dimen name="car_qs_footer_user_switch_icon_width">36dp</dimen> <dimen name="car_qs_footer_user_name_text_size">@dimen/car_body2_size</dimen> + <dimen name="car_user_switcher_container_height">420dp</dimen> + <!-- This must be the negative of car_user_switcher_container_height for the animation. --> + <dimen name="car_user_switcher_container_anim_height">-420dp</dimen> + <dimen name="car_user_grid_margin_bottom">28dp</dimen> + <dimen name="car_body2_size">26sp</dimen> </resources> diff --git a/packages/SystemUI/res/values/integers_car.xml b/packages/SystemUI/res/values/integers_car.xml index 320ee9f66c79..f84dd4bd5f27 100644 --- a/packages/SystemUI/res/values/integers_car.xml +++ b/packages/SystemUI/res/values/integers_car.xml @@ -19,4 +19,5 @@ <integer name="car_user_switcher_timeout_ms">15000</integer> <!-- This values less than ProgressBar.PROGRESS_ANIM_DURATION for a smooth animation. --> <integer name="car_user_switcher_anim_update_ms">60</integer> + <integer name="car_user_switcher_anim_cascade_delay_ms">27</integer> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java index 142aab2626a6..23d3ebbbfe80 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java @@ -47,7 +47,7 @@ public class CarQSFooter extends RelativeLayout implements QSFooter, private MultiUserSwitch mMultiUserSwitch; private TextView mUserName; private ImageView mMultiUserAvatar; - private UserGridView mUserGridView; + private CarQSFragment.UserSwitchCallback mUserSwitchCallback; public CarQSFooter(Context context, AttributeSet attrs) { super(context, attrs); @@ -63,15 +63,15 @@ public class CarQSFooter extends RelativeLayout implements QSFooter, mUserInfoController = Dependency.get(UserInfoController.class); mMultiUserSwitch.setOnClickListener(v -> { - if (mUserGridView == null) { + if (mUserSwitchCallback == null) { Log.e(TAG, "CarQSFooter not properly set up; cannot display user switcher."); return; } - if (!mUserGridView.isShowing()) { - mUserGridView.show(); + if (!mUserSwitchCallback.isShowing()) { + mUserSwitchCallback.show(); } else { - mUserGridView.hide(); + mUserSwitchCallback.hide(); } }); @@ -102,8 +102,8 @@ public class CarQSFooter extends RelativeLayout implements QSFooter, } } - public void setUserGridView(UserGridView view) { - mUserGridView = view; + public void setUserSwitchCallback(CarQSFragment.UserSwitchCallback callback) { + mUserSwitchCallback = callback; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java index 13298d378845..0ee6d1fb6664 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java @@ -13,6 +13,12 @@ */ package com.android.systemui.qs.car; +import android.animation.Animator; +import android.animation.AnimatorInflater; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; import android.app.Fragment; import android.os.Bundle; import android.support.annotation.Nullable; @@ -26,18 +32,29 @@ import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.plugins.qs.QS; import com.android.systemui.qs.QSFooter; +import com.android.systemui.statusbar.car.PageIndicator; import com.android.systemui.statusbar.car.UserGridView; import com.android.systemui.statusbar.policy.UserSwitcherController; +import java.util.ArrayList; +import java.util.List; + /** * A quick settings fragment for the car. For auto, there is no row for quick settings or ability * to expand the quick settings panel. Instead, the only thing is that displayed is the * status bar, and a static row with access to the user switcher and settings. */ public class CarQSFragment extends Fragment implements QS { + private ViewGroup mPanel; private View mHeader; + private View mUserSwitcherContainer; private CarQSFooter mFooter; + private View mFooterUserName; + private View mFooterExpandIcon; private UserGridView mUserGridView; + private PageIndicator mPageIndicator; + private AnimatorSet mAnimatorSet; + private UserSwitchCallback mUserSwitchCallback; @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @@ -48,14 +65,26 @@ public class CarQSFragment extends Fragment implements QS { @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + mPanel = (ViewGroup) view; mHeader = view.findViewById(R.id.header); mFooter = view.findViewById(R.id.qs_footer); + mFooterUserName = mFooter.findViewById(R.id.user_name); + mFooterExpandIcon = mFooter.findViewById(R.id.user_switch_expand_icon); + + mUserSwitcherContainer = view.findViewById(R.id.user_switcher_container); + + updateUserSwitcherHeight(0); mUserGridView = view.findViewById(R.id.user_grid); mUserGridView.init(null, Dependency.get(UserSwitcherController.class), - false /* showInitially */); + false /* overrideAlpha */); - mFooter.setUserGridView(mUserGridView); + mPageIndicator = view.findViewById(R.id.user_switcher_page_indicator); + mPageIndicator.setupWithViewPager(mUserGridView); + + mUserSwitchCallback = new UserSwitchCallback(); + mFooter.setUserSwitchCallback(mUserSwitchCallback); + mUserGridView.setUserSwitchCallback(mUserSwitchCallback); } @Override @@ -82,11 +111,13 @@ public class CarQSFragment extends Fragment implements QS { @Override public void setHeaderListening(boolean listening) { mFooter.setListening(listening); + mUserGridView.setListening(listening); } @Override public void setListening(boolean listening) { mFooter.setListening(listening); + mUserGridView.setListening(listening); } @Override @@ -171,4 +202,126 @@ public class CarQSFragment extends Fragment implements QS { public void setExpandClickListener(OnClickListener onClickListener) { // No ability to expand the quick settings. } + + public class UserSwitchCallback { + private boolean mShowing; + + public boolean isShowing() { + return mShowing; + } + + public void show() { + mShowing = true; + animateHeightChange(true /* opening */); + } + + public void hide() { + mShowing = false; + animateHeightChange(false /* opening */); + } + + public void resetShowing() { + if (mShowing) { + for (int i = 0; i < mUserGridView.getChildCount(); i++) { + ViewGroup podContainer = (ViewGroup) mUserGridView.getChildAt(i); + // Need to bring the last child to the front to maintain the order in the pod + // container. Why? ¯\_(ツ)_/¯ + if (podContainer.getChildCount() > 0) { + podContainer.getChildAt(podContainer.getChildCount() - 1).bringToFront(); + } + // The alpha values are default to 0, so if the pods have been refreshed, they + // need to be set to 1 when showing. + for (int j = 0; j < podContainer.getChildCount(); j++) { + podContainer.getChildAt(j).setAlpha(1f); + } + } + } + } + } + + private void updateUserSwitcherHeight(int height) { + ViewGroup.LayoutParams layoutParams = mUserSwitcherContainer.getLayoutParams(); + layoutParams.height = height; + mUserSwitcherContainer.requestLayout(); + } + + private void animateHeightChange(boolean opening) { + // Animation in progress; cancel it to avoid contention. + if (mAnimatorSet != null){ + mAnimatorSet.cancel(); + } + + List<Animator> allAnimators = new ArrayList<>(); + ValueAnimator heightAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(getContext(), + opening ? R.anim.car_user_switcher_open_animation + : R.anim.car_user_switcher_close_animation); + heightAnimator.addUpdateListener(valueAnimator -> { + updateUserSwitcherHeight((Integer) valueAnimator.getAnimatedValue()); + }); + allAnimators.add(heightAnimator); + + // The user grid contains pod containers that each contain a number of pods. Animate + // all pods to avoid any discrepancy/race conditions with possible changes during the + // animation. + int cascadeDelay = getResources().getInteger( + R.integer.car_user_switcher_anim_cascade_delay_ms); + for (int i = 0; i < mUserGridView.getChildCount(); i++) { + ViewGroup podContainer = (ViewGroup) mUserGridView.getChildAt(i); + for (int j = 0; j < podContainer.getChildCount(); j++) { + View pod = podContainer.getChildAt(j); + Animator podAnimator = AnimatorInflater.loadAnimator(getContext(), + opening ? R.anim.car_user_switcher_open_pod_animation + : R.anim.car_user_switcher_close_pod_animation); + // Add the cascading delay between pods + if (opening) { + podAnimator.setStartDelay(podAnimator.getStartDelay() + j * cascadeDelay); + } + podAnimator.setTarget(pod); + allAnimators.add(podAnimator); + } + } + + Animator nameAnimator = AnimatorInflater.loadAnimator(getContext(), + opening ? R.anim.car_user_switcher_open_name_animation + : R.anim.car_user_switcher_close_name_animation); + nameAnimator.setTarget(mFooterUserName); + allAnimators.add(nameAnimator); + + Animator iconAnimator = AnimatorInflater.loadAnimator(getContext(), + opening ? R.anim.car_user_switcher_open_icon_animation + : R.anim.car_user_switcher_close_icon_animation); + iconAnimator.setTarget(mFooterExpandIcon); + allAnimators.add(iconAnimator); + + Animator pageAnimator = AnimatorInflater.loadAnimator(getContext(), + opening ? R.anim.car_user_switcher_open_pages_animation + : R.anim.car_user_switcher_close_pages_animation); + pageAnimator.setTarget(mPageIndicator); + allAnimators.add(pageAnimator); + + mAnimatorSet = new AnimatorSet(); + mAnimatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mAnimatorSet = null; + } + }); + mAnimatorSet.playTogether(allAnimators.toArray(new Animator[0])); + + // Setup all values to the start values in the animations, since there are delays, but need + // to have all values start at the beginning. + setupInitialValues(mAnimatorSet); + + mAnimatorSet.start(); + } + + private void setupInitialValues(Animator anim) { + if (anim instanceof AnimatorSet) { + for (Animator a : ((AnimatorSet) anim).getChildAnimations()) { + setupInitialValues(a); + } + } else if (anim instanceof ObjectAnimator) { + ((ObjectAnimator) anim).setCurrentFraction(0.0f); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java index 172c62a99db2..3ec89138d1c0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java @@ -53,7 +53,7 @@ public class FullscreenUserSwitcher { mParent = containerStub.inflate(); mContainer = mParent.findViewById(R.id.container); mUserGridView = mContainer.findViewById(R.id.user_grid); - mUserGridView.init(statusBar, mUserSwitcherController, true /* showInitially */); + mUserGridView.init(statusBar, mUserSwitcherController, true /* overrideAlpha */); mUserGridView.setUserSelectionListener(record -> { if (!record.isCurrent) { toggleSwitchInProgress(true); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java index e551801ca434..1bd820db3f7c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java @@ -16,9 +16,6 @@ package com.android.systemui.statusbar.car; -import android.animation.Animator; -import android.animation.Animator.AnimatorListener; -import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; @@ -29,62 +26,110 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; -import android.support.v4.view.animation.FastOutSlowInInterpolator; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.TextView; +import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.qs.car.CarQSFragment; import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.statusbar.policy.UserSwitcherController; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Vector; + /** * Displays a ViewPager with icons for the users in the system to allow switching between users. * One of the uses of this is for the lock screen in auto. */ -public class UserGridView extends ViewPager { - private static final int EXPAND_ANIMATION_TIME_MS = 200; - private static final int HIDE_ANIMATION_TIME_MS = 133; - +public class UserGridView extends ViewPager implements + UserInfoController.OnUserInfoChangedListener { private StatusBar mStatusBar; private UserSwitcherController mUserSwitcherController; private Adapter mAdapter; private UserSelectionListener mUserSelectionListener; - private ValueAnimator mHeightAnimator; - private int mTargetHeight; - private int mHeightChildren; - private boolean mShowing; + private UserInfoController mUserInfoController; + private Vector mUserContainers; + private int mContainerWidth; + private boolean mOverrideAlpha; + private CarQSFragment.UserSwitchCallback mUserSwitchCallback; public UserGridView(Context context, AttributeSet attrs) { super(context, attrs); } public void init(StatusBar statusBar, UserSwitcherController userSwitcherController, - boolean showInitially) { + boolean overrideAlpha) { mStatusBar = statusBar; mUserSwitcherController = userSwitcherController; mAdapter = new Adapter(mUserSwitcherController); - addOnLayoutChangeListener(mAdapter); - setAdapter(mAdapter); - mShowing = showInitially; + mUserInfoController = Dependency.get(UserInfoController.class); + mOverrideAlpha = overrideAlpha; + // Whenever the container width changes, the containers must be refreshed. Instead of + // doing an initial refreshContainers() to populate the containers, this listener will + // refresh them on layout change because that affects how the users are split into + // containers. Furthermore, at this point, the container width is unknown, so + // refreshContainers() cannot populate any containers. + addOnLayoutChangeListener( + (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { + int newWidth = Math.max(left - right, right - left); + if (mContainerWidth != newWidth) { + mContainerWidth = newWidth; + refreshContainers(); + } + }); } - public boolean isShowing() { - return mShowing; + private void refreshContainers() { + mUserContainers = new Vector(); + + Context context = getContext(); + LayoutInflater inflater = LayoutInflater.from(context); + + for (int i = 0; i < mAdapter.getCount(); i++) { + ViewGroup pods = (ViewGroup) inflater.inflate( + R.layout.car_fullscreen_user_pod_container, null); + + int iconsPerPage = mAdapter.getIconsPerPage(); + int limit = Math.min(mUserSwitcherController.getUsers().size(), (i + 1) * iconsPerPage); + for (int j = i * iconsPerPage; j < limit; j++) { + View v = mAdapter.makeUserPod(inflater, context, j, pods); + if (mOverrideAlpha) { + v.setAlpha(1f); + } + pods.addView(v); + // This is hacky, but the dividers on the pod container LinearLayout don't seem + // to work for whatever reason. Instead, set a right margin on the pod if it's not + // the right-most pod and there is more than one pod in the container. + if (i < limit - 1 && limit > 1) { + ViewGroup.MarginLayoutParams params = + (ViewGroup.MarginLayoutParams) v.getLayoutParams(); + params.setMargins(0, 0, getResources().getDimensionPixelSize( + R.dimen.car_fullscreen_user_pod_margin_between), 0); + v.setLayoutParams(params); + } + } + mUserContainers.add(pods); + } + + mAdapter = new Adapter(mUserSwitcherController); + setAdapter(mAdapter); } - public void show() { - mShowing = true; - animateHeightChange(getMeasuredHeight(), mHeightChildren); + @Override + public void onUserInfoChanged(String name, Drawable picture, String userAccount) { + refreshContainers(); } - public void hide() { - mShowing = false; - animateHeightChange(getMeasuredHeight(), 0); + public void setUserSwitchCallback(CarQSFragment.UserSwitchCallback callback) { + mUserSwitchCallback = callback; } public void onUserSwitched(int newUserId) { @@ -96,6 +141,14 @@ public class UserGridView extends ViewPager { mUserSelectionListener = userSelectionListener; } + public void setListening(boolean listening) { + if (listening) { + mUserInfoController.addCallback(this); + } else { + mUserInfoController.removeCallback(this); + } + } + void showOfflineAuthUi() { // TODO: Show keyguard UI in-place. mStatusBar.executeRunnableDismissingKeyguard(null, null, true, true, true); @@ -115,13 +168,6 @@ public class UserGridView extends ViewPager { height = Math.max(child.getMeasuredHeight(), height); } - mHeightChildren = height; - - // Override the height if it's not showing. - if (!mShowing) { - height = 0; - } - // Respect the AT_MOST request from parent. if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) { height = Math.min(MeasureSpec.getSize(heightMeasureSpec), height); @@ -132,72 +178,19 @@ public class UserGridView extends ViewPager { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } - private void animateHeightChange(int oldHeight, int newHeight) { - // If there is no change in height or an animation is already in progress towards the - // desired height, then there's no need to make any changes. - if (oldHeight == newHeight || newHeight == mTargetHeight) { - return; - } - - // Animation in progress is not going towards the new target, so cancel it. - if (mHeightAnimator != null){ - mHeightAnimator.cancel(); - } - - mTargetHeight = newHeight; - mHeightAnimator = ValueAnimator.ofInt(oldHeight, mTargetHeight); - mHeightAnimator.addUpdateListener(valueAnimator -> { - ViewGroup.LayoutParams layoutParams = getLayoutParams(); - layoutParams.height = (Integer) valueAnimator.getAnimatedValue(); - requestLayout(); - }); - mHeightAnimator.addListener(new AnimatorListener() { - @Override - public void onAnimationStart(Animator animator) {} - - @Override - public void onAnimationEnd(Animator animator) { - // ValueAnimator does not guarantee that the update listener will get an update - // to the final value, so here, the final value is set. Though the final calculated - // height (mTargetHeight) could be set, WRAP_CONTENT is more appropriate. - ViewGroup.LayoutParams layoutParams = getLayoutParams(); - layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; - requestLayout(); - mHeightAnimator = null; - } - - @Override - public void onAnimationCancel(Animator animator) {} - - @Override - public void onAnimationRepeat(Animator animator) {} - }); - - mHeightAnimator.setInterpolator(new FastOutSlowInInterpolator()); - if (oldHeight < newHeight) { - // Expanding - mHeightAnimator.setDuration(EXPAND_ANIMATION_TIME_MS); - } else { - // Hiding - mHeightAnimator.setDuration(HIDE_ANIMATION_TIME_MS); - } - mHeightAnimator.start(); - } - /** * This is a ViewPager.PagerAdapter which deletegates the work to a * UserSwitcherController.BaseUserAdapter. Java doesn't support multiple inheritance so we have * to use composition instead to achieve the same goal since both the base classes are abstract * classes and not interfaces. */ - private final class Adapter extends PagerAdapter implements View.OnLayoutChangeListener { + private final class Adapter extends PagerAdapter { private final int mPodWidth; private final int mPodMarginBetween; private final int mPodImageAvatarWidth; private final int mPodImageAvatarHeight; private final WrappedBaseUserAdapter mUserAdapter; - private int mContainerWidth; public Adapter(UserSwitcherController controller) { super(); @@ -229,30 +222,20 @@ public class UserGridView extends ViewPager { } @Override - public Object instantiateItem(ViewGroup container, int position) { - Context context = getContext(); - LayoutInflater inflater = LayoutInflater.from(context); - - ViewGroup pods = (ViewGroup) inflater.inflate( - R.layout.car_fullscreen_user_pod_container, null); + public void finishUpdate(ViewGroup container) { + if (mUserSwitchCallback != null) { + mUserSwitchCallback.resetShowing(); + } + } - int iconsPerPage = getIconsPerPage(); - int limit = Math.min(mUserAdapter.getCount(), (position + 1) * iconsPerPage); - for (int i = position * iconsPerPage; i < limit; i++) { - View v = makeUserPod(inflater, context, i, pods); - pods.addView(v); - // This is hacky, but the dividers on the pod container LinearLayout don't seem - // to work for whatever reason. Instead, set a right margin on the pod if it's not - // the right-most pod and there is more than one pod in the container. - if (i < limit - 1 && limit > 1) { - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( - LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - params.setMargins(0, 0, mPodMarginBetween, 0); - v.setLayoutParams(params); - } + @Override + public Object instantiateItem(ViewGroup container, int position) { + if (position < mUserContainers.size()) { + container.addView((View) mUserContainers.get(position)); + return mUserContainers.get(position); + } else { + return null; } - container.addView(pods); - return pods; } /** @@ -353,17 +336,10 @@ public class UserGridView extends ViewPager { public boolean isViewFromObject(View view, Object object) { return view == object; } - - @Override - public void onLayoutChange(View v, int left, int top, int right, int bottom, - int oldLeft, int oldTop, int oldRight, int oldBottom) { - mContainerWidth = Math.max(left - right, right - left); - notifyDataSetChanged(); - } } private final class WrappedBaseUserAdapter extends UserSwitcherController.BaseUserAdapter { - private Adapter mContainer; + private final Adapter mContainer; public WrappedBaseUserAdapter(UserSwitcherController controller, Adapter container) { super(controller); |