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

Commit 9d250013 authored by Bryan Eyler's avatar Bryan Eyler Committed by android-build-merger
Browse files

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

am: d188dd73

Change-Id: I42331c5559df69c179239c8cad6f2c39fabb7bf3
parents f3744461 d188dd73
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -24,4 +24,11 @@


    <include layout="@layout/car_status_bar_header" />
    <include layout="@layout/car_status_bar_header" />
    <include layout="@layout/car_qs_footer" />
    <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>
</LinearLayout>
+22 −0
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@ import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.View;
import android.widget.ImageView;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout;
@@ -27,6 +28,7 @@ import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSFooter;
import com.android.systemui.qs.QSFooter;
import com.android.systemui.qs.QSPanel;
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.phone.MultiUserSwitch;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.UserInfoController;
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,
public class CarQSFooter extends RelativeLayout implements QSFooter,
        UserInfoController.OnUserInfoChangedListener {
        UserInfoController.OnUserInfoChangedListener {
    private static final String TAG = "CarQSFooter";

    private UserInfoController mUserInfoController;
    private UserInfoController mUserInfoController;


    private MultiUserSwitch mMultiUserSwitch;
    private MultiUserSwitch mMultiUserSwitch;
    private ImageView mMultiUserAvatar;
    private ImageView mMultiUserAvatar;
    private UserGridView mUserGridView;


    public CarQSFooter(Context context, AttributeSet attrs) {
    public CarQSFooter(Context context, AttributeSet attrs) {
        super(context, attrs);
        super(context, attrs);
@@ -54,6 +59,19 @@ public class CarQSFooter extends RelativeLayout implements QSFooter,


        mUserInfoController = Dependency.get(UserInfoController.class);
        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 -> {
        findViewById(R.id.settings_button).setOnClickListener(v -> {
            ActivityStarter activityStarter = Dependency.get(ActivityStarter.class);
            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
    @Override
    public void setListening(boolean listening) {
    public void setListening(boolean listening) {
        if (listening) {
        if (listening) {
+11 −1
Original line number Original line Diff line number Diff line
@@ -22,9 +22,12 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup;


import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.QSFooter;
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
 * 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 {
public class CarQSFragment extends Fragment implements QS {
    private View mHeader;
    private View mHeader;
    private QSFooter mFooter;
    private CarQSFooter mFooter;
    private UserGridView mUserGridView;


    @Override
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@@ -46,6 +50,12 @@ public class CarQSFragment extends Fragment implements QS {
        super.onViewCreated(view, savedInstanceState);
        super.onViewCreated(view, savedInstanceState);
        mHeader = view.findViewById(R.id.header);
        mHeader = view.findViewById(R.id.header);
        mFooter = view.findViewById(R.id.qs_footer);
        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
    @Override
+1 −1
Original line number Original line Diff line number Diff line
@@ -53,7 +53,7 @@ public class FullscreenUserSwitcher {
        mParent = containerStub.inflate();
        mParent = containerStub.inflate();
        mContainer = mParent.findViewById(R.id.container);
        mContainer = mParent.findViewById(R.id.container);
        mUserGridView = mContainer.findViewById(R.id.user_grid);
        mUserGridView = mContainer.findViewById(R.id.user_grid);
        mUserGridView.init(statusBar, mUserSwitcherController);
        mUserGridView.init(statusBar, mUserSwitcherController, true /* showInitially */);
        mUserGridView.setUserSelectionListener(record -> {
        mUserGridView.setUserSelectionListener(record -> {
            if (!record.isCurrent) {
            if (!record.isCurrent) {
                toggleSwitchInProgress(true);
                toggleSwitchInProgress(true);
+102 −11
Original line number Original line Diff line number Diff line
@@ -16,20 +16,21 @@


package com.android.systemui.statusbar.car;
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.Context;
import android.content.res.Resources;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Align;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.GradientDrawable;
import android.os.UserHandle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.util.AttributeSet;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup;
@@ -37,9 +38,7 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.TextView;


import com.android.internal.util.UserIcons;
import com.android.systemui.R;
import com.android.systemui.R;
import com.android.systemui.statusbar.UserUtil;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.UserSwitcherController;
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.
 * One of the uses of this is for the lock screen in auto.
 */
 */
public class UserGridView extends ViewPager {
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 StatusBar mStatusBar;
    private UserSwitcherController mUserSwitcherController;
    private UserSwitcherController mUserSwitcherController;
    private Adapter mAdapter;
    private Adapter mAdapter;
    private UserSelectionListener mUserSelectionListener;
    private UserSelectionListener mUserSelectionListener;
    private ValueAnimator mHeightAnimator;
    private int mTargetHeight;
    private int mHeightChildren;
    private boolean mShowing;


    public UserGridView(Context context, AttributeSet attrs) {
    public UserGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
        super(context, attrs);
    }
    }


    public void init(StatusBar statusBar, UserSwitcherController userSwitcherController) {
    public void init(StatusBar statusBar, UserSwitcherController userSwitcherController,
            boolean showInitially) {
        mStatusBar = statusBar;
        mStatusBar = statusBar;
        mUserSwitcherController = userSwitcherController;
        mUserSwitcherController = userSwitcherController;
        mAdapter = new Adapter(mUserSwitcherController);
        mAdapter = new Adapter(mUserSwitcherController);
        addOnLayoutChangeListener(mAdapter);
        addOnLayoutChangeListener(mAdapter);
        setAdapter(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) {
    public void onUserSwitched(int newUserId) {
@@ -83,16 +105,85 @@ public class UserGridView extends ViewPager {
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // Wrap content doesn't work in ViewPagers, so simulate the behavior in code.
        // Wrap content doesn't work in ViewPagers, so simulate the behavior in code.
        int height = 0;
        int height = 0;
        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
            height = MeasureSpec.getSize(heightMeasureSpec);
        } else {
            for (int i = 0; i < getChildCount(); i++) {
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                View child = getChildAt(i);
                child.measure(widthMeasureSpec,
                child.measure(widthMeasureSpec,
                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
                height = Math.max(child.getMeasuredHeight(), height);
                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);
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        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
     * This is a ViewPager.PagerAdapter which deletegates the work to a
     * UserSwitcherController.BaseUserAdapter. Java doesn't support multiple inheritance so we have
     * UserSwitcherController.BaseUserAdapter. Java doesn't support multiple inheritance so we have