diff options
| author | 2017-08-08 16:53:33 -0700 | |
|---|---|---|
| committer | 2017-08-17 13:36:59 -0700 | |
| commit | 2ff95846dae60c6c4ddffa3ce5a34687d9f88d3b (patch) | |
| tree | d7d4a77b91a34f37d119948f921ab0845ca55cd1 | |
| parent | 1b08a4a8a3271f04b98c34747fe077610b7ee534 (diff) | |
Add user selection to car status bar and animate.
Adds the UserGridView to the car status bar and adds an animation when
expanding/hiding.
Bug: 63593747
Tested on Mojave with the fullscreen user switcher and status bar.
Change-Id: If6ddbd4da896c5eb661393dcc35ab299361754e9
5 files changed, 143 insertions, 13 deletions
diff --git a/packages/SystemUI/res/layout/car_qs_panel.xml b/packages/SystemUI/res/layout/car_qs_panel.xml index d1f7ff83db93..0b46b0bdaa1c 100644 --- a/packages/SystemUI/res/layout/car_qs_panel.xml +++ b/packages/SystemUI/res/layout/car_qs_panel.xml @@ -24,4 +24,11 @@ <include layout="@layout/car_status_bar_header" /> <include layout="@layout/car_qs_footer" /> + + <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" /> </LinearLayout> 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 9730f29da977..d42b87bcef28 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java @@ -18,6 +18,7 @@ import android.content.Intent; import android.graphics.drawable.Drawable; import android.support.annotation.Nullable; import android.util.AttributeSet; +import android.util.Log; import android.view.View; import android.widget.ImageView; import android.widget.RelativeLayout; @@ -27,6 +28,7 @@ import com.android.systemui.R; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.qs.QSFooter; import com.android.systemui.qs.QSPanel; +import com.android.systemui.statusbar.car.UserGridView; import com.android.systemui.statusbar.phone.MultiUserSwitch; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.UserInfoController; @@ -37,10 +39,13 @@ import com.android.systemui.statusbar.policy.UserInfoController; */ public class CarQSFooter extends RelativeLayout implements QSFooter, UserInfoController.OnUserInfoChangedListener { + private static final String TAG = "CarQSFooter"; + private UserInfoController mUserInfoController; private MultiUserSwitch mMultiUserSwitch; private ImageView mMultiUserAvatar; + private UserGridView mUserGridView; public CarQSFooter(Context context, AttributeSet attrs) { super(context, attrs); @@ -54,6 +59,19 @@ public class CarQSFooter extends RelativeLayout implements QSFooter, mUserInfoController = Dependency.get(UserInfoController.class); + mMultiUserSwitch.setOnClickListener(v -> { + if (mUserGridView == null) { + Log.e(TAG, "CarQSFooter not properly set up; cannot display user switcher."); + return; + } + + if (!mUserGridView.isShowing()) { + mUserGridView.show(); + } else { + mUserGridView.hide(); + } + }); + findViewById(R.id.settings_button).setOnClickListener(v -> { ActivityStarter activityStarter = Dependency.get(ActivityStarter.class); @@ -80,6 +98,10 @@ public class CarQSFooter extends RelativeLayout implements QSFooter, } } + public void setUserGridView(UserGridView view) { + mUserGridView = view; + } + @Override public void setListening(boolean listening) { if (listening) { 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 7c2a8129813a..13298d378845 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java @@ -22,9 +22,12 @@ import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; +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.UserGridView; +import com.android.systemui.statusbar.policy.UserSwitcherController; /** * A quick settings fragment for the car. For auto, there is no row for quick settings or ability @@ -33,7 +36,8 @@ import com.android.systemui.qs.QSFooter; */ public class CarQSFragment extends Fragment implements QS { private View mHeader; - private QSFooter mFooter; + private CarQSFooter mFooter; + private UserGridView mUserGridView; @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @@ -46,6 +50,12 @@ public class CarQSFragment extends Fragment implements QS { super.onViewCreated(view, savedInstanceState); 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 */); + + mFooter.setUserGridView(mUserGridView); } @Override 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 6060134de6da..172c62a99db2 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); + mUserGridView.init(statusBar, mUserSwitcherController, true /* showInitially */); 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 f178aa634247..e551801ca434 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java @@ -16,20 +16,21 @@ 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; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; -import android.os.UserHandle; 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.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -37,9 +38,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import com.android.internal.util.UserIcons; import com.android.systemui.R; -import com.android.systemui.statusbar.UserUtil; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.UserSwitcherController; @@ -48,21 +47,44 @@ import com.android.systemui.statusbar.policy.UserSwitcherController; * 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) { + public void init(StatusBar statusBar, UserSwitcherController userSwitcherController, + boolean showInitially) { 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) { @@ -83,16 +105,85 @@ public class UserGridView extends ViewPager { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // Wrap content doesn't work in ViewPagers, so simulate the behavior in code. int height = 0; - for(int i = 0; i < getChildCount(); i++) { - View child = getChildAt(i); - child.measure(widthMeasureSpec, - MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); - height = Math.max(child.getMeasuredHeight(), height); + if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) { + height = MeasureSpec.getSize(heightMeasureSpec); + } else { + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + child.measure(widthMeasureSpec, + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + 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); + } } heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); + 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 |