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

Commit 7adbc2c6 authored by Ivan Tkachenko's avatar Ivan Tkachenko Committed by Android (Google) Code Review
Browse files

Merge "Add handle view to bubble bar expanded view" into udc-qpr-dev

parents de765c22 67c50ee7
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@
    <color name="bubbles_light">#FFFFFF</color>
    <color name="bubbles_dark">@color/GM2_grey_800</color>
    <color name="bubbles_icon_tint">@color/GM2_grey_700</color>
    <color name="bubble_bar_expanded_view_handle_light">#EBffffff</color>
    <color name="bubble_bar_expanded_view_handle_dark">#99000000</color>

    <!-- PiP -->
    <color name="pip_custom_close_bg">#D93025</color>
+5 −1
Original line number Diff line number Diff line
@@ -229,7 +229,11 @@
    <!-- Size of the bubble bar (height), should match transient_taskbar_size in Launcher. -->
    <dimen name="bubblebar_size">72dp</dimen>
    <!-- The size of the drag handle / menu shown along with a bubble bar expanded view. -->
    <dimen name="bubblebar_expanded_view_menu_size">16dp</dimen>
    <dimen name="bubble_bar_expanded_view_handle_size">40dp</dimen>
    <!-- The width of the drag handle shown along with a bubble bar expanded view. -->
    <dimen name="bubble_bar_expanded_view_handle_width">128dp</dimen>
    <!-- The height of the drag handle shown along with a bubble bar expanded view. -->
    <dimen name="bubble_bar_expanded_view_handle_height">4dp</dimen>

    <!-- Bottom and end margin for compat buttons. -->
    <dimen name="compat_button_margin">24dp</dimen>
+44 −31
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.wm.shell.bubbles.bar;

import android.annotation.ColorInt;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.TypedArray;
@@ -46,10 +48,10 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
    private BubbleController mController;
    private BubbleTaskViewHelper mBubbleTaskViewHelper;

    private HandleView mMenuView;
    private TaskView mTaskView;
    private BubbleBarHandleView mHandleView = new BubbleBarHandleView(getContext());
    private @Nullable TaskView mTaskView;

    private int mMenuHeight;
    private int mHandleHeight;
    private int mBackgroundColor;
    private float mCornerRadius = 0f;

@@ -83,11 +85,9 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
        super.onFinishInflate();
        Context context = getContext();
        setElevation(getResources().getDimensionPixelSize(R.dimen.bubble_elevation));
        mMenuHeight = context.getResources().getDimensionPixelSize(
                R.dimen.bubblebar_expanded_view_menu_size);
        mMenuView = new HandleView(context);
        addView(mMenuView);

        mHandleHeight = context.getResources().getDimensionPixelSize(
                R.dimen.bubble_bar_expanded_view_handle_size);
        addView(mHandleView);
        applyThemeAttrs();
        setClipToOutline(true);
        setOutlineProvider(new ViewOutlineProvider() {
@@ -123,14 +123,12 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView

        ta.recycle();

        mMenuView.setCornerRadius(mCornerRadius);
        mMenuHeight = getResources().getDimensionPixelSize(
                R.dimen.bubblebar_expanded_view_menu_size);
        mHandleHeight = getResources().getDimensionPixelSize(
                R.dimen.bubble_bar_expanded_view_handle_size);

        if (mTaskView != null) {
            mTaskView.setCornerRadius(mCornerRadius);
            mTaskView.setElevation(150);
            updateMenuColor();
            updateHandleAndBackgroundColor(true /* animated */);
        }
    }

@@ -138,10 +136,8 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        // Add corner radius here so that the menu extends behind the rounded corners of TaskView.
        int menuViewHeight = Math.min((int) (mMenuHeight + mCornerRadius), height);
        measureChild(mMenuView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(menuViewHeight,
        int menuViewHeight = Math.min(mHandleHeight, height);
        measureChild(mHandleView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(menuViewHeight,
                MeasureSpec.getMode(heightMeasureSpec)));

        if (mTaskView != null) {
@@ -153,12 +149,12 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        // Drag handle above
        final int dragHandleBottom = t + mMenuView.getMeasuredHeight();
        mMenuView.layout(l, t, r, dragHandleBottom);
        final int dragHandleBottom = t + mHandleView.getMeasuredHeight();
        mHandleView.layout(l, t, r, dragHandleBottom);
        if (mTaskView != null) {
            // Subtract radius so that the menu extends behind the rounded corners of TaskView.
            mTaskView.layout(l, (int) (dragHandleBottom - mCornerRadius), r,
            mTaskView.layout(l, dragHandleBottom, r,
                    dragHandleBottom + mTaskView.getMeasuredHeight());
        }
    }
@@ -166,7 +162,7 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
    @Override
    public void onTaskCreated() {
        setContentVisibility(true);
        updateMenuColor();
        updateHandleAndBackgroundColor(false /* animated */);
    }

    @Override
@@ -218,16 +214,33 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
        }
    }

    /** Updates the menu bar to be the status bar color specified by the app. */
    private void updateMenuColor() {
    /**
     * Updates the background color to match with task view status/bg color, and sets handle color
     * to contrast with the background
     */
    private void updateHandleAndBackgroundColor(boolean animated) {
        if (mTaskView == null) return;
        ActivityManager.RunningTaskInfo info = mTaskView.getTaskInfo();
        final int taskBgColor = info.taskDescription.getStatusBarColor();
        final int color = Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).toArgb();
        if (color != -1) {
            mMenuView.setBackgroundColor(color);
        final int color = getTaskViewColor();
        final boolean isRegionDark = Color.luminance(color) <= 0.5;
        mHandleView.updateHandleColor(isRegionDark, animated);
        setBackgroundColor(color);
    }

    /**
     * Retrieves task view status/nav bar color or background if available
     *
     * TODO (b/283075226): Update with color sampling when
     *                     RegionSamplingHelper or alternative is available
     */
    private @ColorInt int getTaskViewColor() {
        if (mTaskView == null || mTaskView.getTaskInfo() == null) return mBackgroundColor;
        ActivityManager.TaskDescription taskDescription = mTaskView.getTaskInfo().taskDescription;
        if (taskDescription.getStatusBarColor() != Color.TRANSPARENT) {
            return taskDescription.getStatusBarColor();
        } else if (taskDescription.getBackgroundColor() != Color.TRANSPARENT) {
            return taskDescription.getBackgroundColor();
        } else {
            mMenuView.setBackgroundColor(mBackgroundColor);
            return mBackgroundColor;
        }
    }

+115 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.
 */
package com.android.wm.shell.bubbles.bar;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Outline;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;

import androidx.annotation.ColorInt;
import androidx.core.content.ContextCompat;

import com.android.wm.shell.R;

/**
 * Handle view to show at the top of a bubble bar expanded view.
 */
public class BubbleBarHandleView extends View {
    private static final long COLOR_CHANGE_DURATION = 120;

    private final int mHandleWidth;
    private final int mHandleHeight;
    private final @ColorInt int mHandleLightColor;
    private final @ColorInt int mHandleDarkColor;
    private @Nullable ObjectAnimator mColorChangeAnim;

    public BubbleBarHandleView(Context context) {
        this(context, null);
    }

    public BubbleBarHandleView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BubbleBarHandleView(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public BubbleBarHandleView(Context context, AttributeSet attrs, int defStyleAttr,
            int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        Resources resources = context.getResources();
        mHandleWidth = resources.getDimensionPixelSize(
                R.dimen.bubble_bar_expanded_view_handle_width);
        mHandleHeight = resources.getDimensionPixelSize(
                R.dimen.bubble_bar_expanded_view_handle_height);
        mHandleLightColor = ContextCompat.getColor(context,
                R.color.bubble_bar_expanded_view_handle_light);
        mHandleDarkColor = ContextCompat.getColor(context,
                R.color.bubble_bar_expanded_view_handle_dark);

        setClipToOutline(true);
        setOutlineProvider(new ViewOutlineProvider() {
            @Override
            public void getOutline(View view, Outline outline) {
                final int handleCenterX = view.getWidth() / 2;
                final int handleCenterY = view.getHeight() / 2;
                final float handleRadius = mHandleHeight / 2f;
                Rect handleBounds = new Rect(
                        handleCenterX - mHandleWidth / 2,
                        handleCenterY - mHandleHeight / 2,
                        handleCenterX + mHandleWidth / 2,
                        handleCenterY + mHandleHeight / 2);
                outline.setRoundRect(handleBounds, handleRadius);
            }
        });
    }

    /**
     * Updates the handle color.
     *
     * @param isRegionDark Whether the background behind the handle is dark, and thus the handle
     *                     should be light (and vice versa).
     * @param animated      Whether to animate the change, or apply it immediately.
     */
    public void updateHandleColor(boolean isRegionDark, boolean animated) {
        int newColor = isRegionDark ? mHandleLightColor : mHandleDarkColor;
        if (mColorChangeAnim != null) {
            mColorChangeAnim.cancel();
        }
        if (animated) {
            mColorChangeAnim = ObjectAnimator.ofArgb(this, "backgroundColor", newColor);
            mColorChangeAnim.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mColorChangeAnim = null;
                }
            });
            mColorChangeAnim.setDuration(COLOR_CHANGE_DURATION);
            mColorChangeAnim.start();
        } else {
            setBackgroundColor(newColor);
        }
    }
}
+0 −42
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.
 */
package com.android.wm.shell.bubbles.bar;

import android.content.Context;
import android.view.Gravity;
import android.widget.LinearLayout;

/**
 * Handle / menu view to show at the top of a bubble bar expanded view.
 */
public class HandleView extends LinearLayout {

    // TODO(b/273307221): implement the manage menu in this view.
    public HandleView(Context context) {
        super(context);
        setOrientation(LinearLayout.HORIZONTAL);
        setGravity(Gravity.CENTER);
    }

    /**
     * The menu extends past the top of the TaskView because of the rounded corners. This means
     * to center content in the menu we must subtract the radius (i.e. the amount of space covered
     * by TaskView).
     */
    public void setCornerRadius(float radius) {
        setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), (int) radius);
    }
}
Loading