Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 04d69537 authored by Bryan Eyler's avatar Bryan Eyler Committed by Android (Google) Code Review
Browse files

Merge "Add user selection to car status bar and animate." into oc-mr1-dev

parents 4796cf6b 2ff95846
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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>
+22 −0
Original line number Diff line number Diff line
@@ -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) {
+11 −1
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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);
+102 −11
Original line number Diff line number Diff line
@@ -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;
        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