Add pagination dots and fix animation of user switcher.

- Adds pagination dots to user switcher dropdown.
- Adds device name text view for when devices are associated with users.
- Fixes the layout of the user grid to handle changing height for
  proper animation.

Bug: 65423882
Tested on Mojave with longer animation times to ensure correctness.

Change-Id: I54ae5cc93f9caa9d6c4a5c2c7e9e2488a6257001
(cherry picked from commit 0de35b5386ad7e00f13a7611fce36ca990b201e0)
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 0000000..da92e85
--- /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_open_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_open_animation.xml
new file mode 100644
index 0000000..8b0e4a5
--- /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/layout/car_fullscreen_user_pod.xml b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
index 2f16516..bc5d37c 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
@@ -15,27 +15,38 @@
      limitations under the License.
 -->
 
-<LinearLayout
+<RelativeLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
     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 99d010f..2f6ad2c 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml
@@ -18,8 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     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 257e281..478b656 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_panel.xml b/packages/SystemUI/res/layout/car_qs_panel.xml
index 4cb0fd5..1eb88a1 100644
--- a/packages/SystemUI/res/layout/car_qs_panel.xml
+++ b/packages/SystemUI/res/layout/car_qs_panel.xml
@@ -26,10 +26,29 @@
     <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: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: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:layout_alignParentBottom="true" />
+
+    </RelativeLayout>
+
 </LinearLayout>
diff --git a/packages/SystemUI/res/values/dimens_car.xml b/packages/SystemUI/res/values/dimens_car.xml
index 8853587..96bcddc 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>
@@ -50,5 +53,8 @@
     <dimen name="car_qs_footer_user_switch_margin_right">46dp</dimen>
     <dimen name="car_qs_footer_user_name_text_size">@dimen/car_body2_size</dimen>
 
+    <dimen name="car_user_switcher_container_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/src/com/android/systemui/qs/car/CarQSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java
index 142aab2..23d3ebbb 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 @@
     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 @@
         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 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 13298d3..58a621a 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,10 @@
  */
 package com.android.systemui.qs.car;
 
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.app.Fragment;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
@@ -26,6 +30,7 @@
 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;
 
@@ -36,8 +41,11 @@
  */
 public class CarQSFragment extends Fragment implements QS {
     private View mHeader;
+    private View mUserSwitcherContainer;
     private CarQSFooter mFooter;
     private UserGridView mUserGridView;
+    private PageIndicator mPageIndicator;
+    private ValueAnimator mHeightAnimator;
 
     @Override
     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@@ -51,11 +59,17 @@
         mHeader = view.findViewById(R.id.header);
         mFooter = view.findViewById(R.id.qs_footer);
 
-        mUserGridView = view.findViewById(R.id.user_grid);
-        mUserGridView.init(null, Dependency.get(UserSwitcherController.class),
-                false /* showInitially */);
+        mUserSwitcherContainer = view.findViewById(R.id.user_switcher_container);
 
-        mFooter.setUserGridView(mUserGridView);
+        updateUserSwitcherHeight(0);
+
+        mUserGridView = view.findViewById(R.id.user_grid);
+        mUserGridView.init(null, Dependency.get(UserSwitcherController.class));
+
+        mPageIndicator = view.findViewById(R.id.user_switcher_page_indicator);
+        mPageIndicator.setupWithViewPager(mUserGridView);
+
+        mFooter.setUserSwitchCallback(new UserSwitchCallback());
     }
 
     @Override
@@ -171,4 +185,49 @@
     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 */);
+        }
+    }
+
+    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 (mHeightAnimator != null){
+            mHeightAnimator.cancel();
+        }
+
+        mHeightAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(getContext(),
+                opening ? R.anim.car_user_switcher_open_animation
+                        : R.anim.car_user_switcher_close_animation);
+        mHeightAnimator.addUpdateListener(valueAnimator -> {
+            updateUserSwitcherHeight((Integer)valueAnimator.getAnimatedValue());
+        });
+        mHeightAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mHeightAnimator = null;
+            }
+        });
+        mHeightAnimator.start();
+    }
 }
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 172c62a..6060134 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 @@
         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);
         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 e551801..e241177 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,13 +26,11 @@
 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.R;
@@ -47,44 +42,21 @@
  * 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;
-
     private StatusBar mStatusBar;
     private UserSwitcherController mUserSwitcherController;
     private Adapter mAdapter;
     private UserSelectionListener mUserSelectionListener;
-    private ValueAnimator mHeightAnimator;
-    private int mTargetHeight;
-    private int mHeightChildren;
-    private boolean mShowing;
 
     public UserGridView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
-    public void init(StatusBar statusBar, UserSwitcherController userSwitcherController,
-            boolean showInitially) {
+    public void init(StatusBar statusBar, UserSwitcherController userSwitcherController) {
         mStatusBar = statusBar;
         mUserSwitcherController = userSwitcherController;
         mAdapter = new Adapter(mUserSwitcherController);
         addOnLayoutChangeListener(mAdapter);
         setAdapter(mAdapter);
-        mShowing = showInitially;
-    }
-
-    public boolean isShowing() {
-        return mShowing;
-    }
-
-    public void show() {
-        mShowing = true;
-        animateHeightChange(getMeasuredHeight(), mHeightChildren);
-    }
-
-    public void hide() {
-        mShowing = false;
-        animateHeightChange(getMeasuredHeight(), 0);
     }
 
     public void onUserSwitched(int newUserId) {
@@ -115,13 +87,6 @@
                 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,58 +97,6 @@
         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
@@ -245,8 +158,8 @@
                 // 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);
+                    ViewGroup.MarginLayoutParams params =
+                            (ViewGroup.MarginLayoutParams) v.getLayoutParams();
                     params.setMargins(0, 0, mPodMarginBetween, 0);
                     v.setLayoutParams(params);
                 }