summaryrefslogtreecommitdiff
path: root/src/com/android/launcher3/allapps/SectionDecorationHandler.java
blob: f79b82cebba55c94ac0cbb0003e1d47510f16433 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/*
 * 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.launcher3.allapps;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.InsetDrawable;
import android.view.View;

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

import com.android.launcher3.R;
import com.android.launcher3.util.Themes;

public class SectionDecorationHandler {

    protected final Path mTmpPath = new Path();
    protected final RectF mTmpRect = new RectF();

    protected final int mCornerGroupRadius;
    protected final int mCornerResultRadius;
    protected final RectF mBounds = new RectF();
    protected final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    protected final int mFocusAlpha = 255; // main focused item alpha
    protected int mFillColor; // grouping color
    protected int mFocusColor; // main focused item color
    protected float mFillSpacing;
    protected int mInlineRadius;
    protected Context mContext;
    protected float[] mCorners;
    protected int mFillAlpha;
    protected boolean mIsTopLeftRound;
    protected boolean mIsTopRightRound;
    protected boolean mIsBottomLeftRound;
    protected boolean mIsBottomRightRound;
    protected boolean mIsBottomRound;
    protected boolean mIsTopRound;

    public SectionDecorationHandler(Context context, int fillAlpha, boolean isTopLeftRound,
            boolean isTopRightRound, boolean isBottomLeftRound,
            boolean isBottomRightRound) {

        mContext = context;
        mFillAlpha = fillAlpha;
        mFocusColor = ContextCompat.getColor(context,
                R.color.material_color_surface_bright); // UX recommended
        mFillColor = ContextCompat.getColor(context,
                R.color.material_color_surface_container_high); // UX recommended

        mIsTopLeftRound = isTopLeftRound;
        mIsTopRightRound = isTopRightRound;
        mIsBottomLeftRound = isBottomLeftRound;
        mIsBottomRightRound = isBottomRightRound;
        mIsBottomRound = mIsBottomLeftRound && mIsBottomRightRound;
        mIsTopRound = mIsTopLeftRound && mIsTopRightRound;

        mCornerGroupRadius = context.getResources().getDimensionPixelSize(
                R.dimen.all_apps_recycler_view_decorator_group_radius);
        mCornerResultRadius = context.getResources().getDimensionPixelSize(
                R.dimen.all_apps_recycler_view_decorator_result_radius);

        mInlineRadius = 0;
        mFillSpacing = 0;
        initCorners();
    }

    protected void initCorners() {
        mCorners = new float[]{
                mIsTopLeftRound ? mCornerGroupRadius : 0,
                mIsTopLeftRound ? mCornerGroupRadius : 0, // Top left radius in px
                mIsTopRightRound ? mCornerGroupRadius : 0,
                mIsTopRightRound ? mCornerGroupRadius : 0, // Top right radius in px
                mIsBottomRightRound ? mCornerGroupRadius : 0,
                mIsBottomRightRound ? mCornerGroupRadius : 0, // Bottom right
                mIsBottomLeftRound ? mCornerGroupRadius : 0,
                mIsBottomLeftRound ? mCornerGroupRadius : 0 // Bottom left
        };
    }

    protected void setFillAlpha(int fillAlpha) {
        mFillAlpha = fillAlpha;
        mPaint.setAlpha(mFillAlpha);
    }

    protected void onFocusDraw(Canvas canvas, @Nullable View view) {
        if (view == null) {
            return;
        }
        mPaint.setColor(mFillColor);
        mPaint.setAlpha(mFillAlpha);
        int scaledHeight = (int) (view.getHeight() * view.getScaleY());
        mBounds.set(view.getLeft(), view.getY(), view.getRight(), view.getY() + scaledHeight);
        onDraw(canvas);
    }

    protected void onDraw(Canvas canvas) {
        mTmpPath.reset();
        mTmpRect.set(mBounds.left + mFillSpacing,
                mBounds.top + mFillSpacing,
                mBounds.right - mFillSpacing,
                mBounds.bottom - mFillSpacing);
        mTmpPath.addRoundRect(mTmpRect, mCorners, Path.Direction.CW);
        canvas.drawPath(mTmpPath, mPaint);
    }

    /** Sets the right background drawable to the view based on the give decoration info. */
    public void applyBackground(View view, Context context,
           @Nullable SectionDecorationInfo decorationInfo, boolean isHighlighted) {
        int inset = context.getResources().getDimensionPixelSize(
                R.dimen.all_apps_recycler_view_decorator_padding);
        float radiusBottom = (decorationInfo == null || decorationInfo.isBottomRound()) ?
                mCornerGroupRadius : mCornerResultRadius;
        float radiusTop =
                (decorationInfo == null || decorationInfo.isTopRound()) ?
                        mCornerGroupRadius : mCornerResultRadius;
        int color = isHighlighted ? mFocusColor : mFillColor;

        GradientDrawable shape = new GradientDrawable();
        shape.setShape(GradientDrawable.RECTANGLE);
        shape.setCornerRadii(new float[] {
                radiusTop, radiusTop, // top-left
                radiusTop, radiusTop, // top-right
                radiusBottom, radiusBottom, // bottom-right
                radiusBottom, radiusBottom // bottom-left
        });
        shape.setColor(color);

        // Setting the background resets the padding, so we cache it and reset it afterwards.
        int paddingLeft = view.getPaddingLeft();
        int paddingTop = view.getPaddingTop();
        int paddingRight = view.getPaddingRight();
        int paddingBottom = view.getPaddingBottom();

        view.setBackground(new InsetDrawable(shape, inset));

        view.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
    }

    /**
     * Section decorator that combines views and draws a single block decoration
     */
    public static class UnionDecorationHandler extends SectionDecorationHandler {

        private final int mPaddingLeft;
        private final int mPaddingRight;

        public UnionDecorationHandler(
                SectionDecorationHandler decorationHandler,
                int paddingLeft, int paddingRight) {
            super(decorationHandler.mContext, decorationHandler.mFillAlpha,
                    decorationHandler.mIsTopLeftRound, decorationHandler.mIsTopRightRound,
                    decorationHandler.mIsBottomLeftRound, decorationHandler.mIsBottomRightRound);
            mPaddingLeft = paddingLeft;
            mPaddingRight = paddingRight;
        }

        /**
         * Expands decoration bounds to include child {@link PrivateAppsSectionDecorator}
         */
        public void addChild(SectionDecorationHandler child, View view, boolean applyBackground) {
            int scaledHeight = (int) (view.getHeight() * view.getScaleY());
            mBounds.union(view.getLeft(), view.getY(),
                    view.getRight(), view.getY() + scaledHeight);
            if (applyBackground) {
                applyBackground(view, mContext, null, false);
            }
            mIsBottomRound |= child.mIsBottomRound;
            mIsBottomLeftRound |= child.mIsBottomLeftRound;
            mIsBottomRightRound |= child.mIsBottomRightRound;
            mIsTopRound |= child.mIsTopRound;
            mIsTopLeftRound |= child.mIsTopLeftRound;
            mIsTopRightRound |= child.mIsTopRightRound;
        }

        /**
         * Draws group decoration to canvas
         */
        public void onGroupDecorate(Canvas canvas) {
            initCorners();
            mBounds.left = mPaddingLeft;
            mBounds.right = canvas.getWidth() - mPaddingRight;
            mPaint.setColor(mFillColor);
            mPaint.setAlpha(mFillAlpha);
            onDraw(canvas);
        }
    }
}