• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.customization.picker.color.ui.view
17 
18 import android.annotation.ColorInt
19 import android.content.Context
20 import android.graphics.Canvas
21 import android.graphics.Color
22 import android.graphics.Paint
23 import android.graphics.Path
24 import android.util.AttributeSet
25 import com.android.themepicker.R
26 import com.android.wallpaper.picker.option.ui.view.OptionItemBackground
27 
28 /**
29  * Draw a color option icon, which is a quadrant circle that can show at most 4 different colors.
30  */
31 class ColorOptionIconView2(context: Context, attrs: AttributeSet) :
32     OptionItemBackground(context, attrs) {
33 
<lambda>null34     private val paint = Paint().apply { style = Paint.Style.FILL }
35 
36     private val path = Path()
37 
38     private var color0 = DEFAULT_PLACEHOLDER_COLOR
39     private var color1 = DEFAULT_PLACEHOLDER_COLOR
40     private var color2 = DEFAULT_PLACEHOLDER_COLOR
41     private var color3 = DEFAULT_PLACEHOLDER_COLOR
42     private var strokeColor = DEFAULT_PLACEHOLDER_COLOR
43     private val strokeWidth =
44         context.resources
45             .getDimensionPixelSize(R.dimen.floating_sheet_color_option_stroke_width)
46             .toFloat()
47 
48     private var w = 0
49     private var h = 0
50 
51     /**
52      * @param color0 the color in the top left quadrant
53      * @param color1 the color in the top right quadrant
54      * @param color2 the color in the bottom left quadrant
55      * @param color3 the color in the bottom right quadrant
56      */
bindColornull57     fun bindColor(
58         @ColorInt color0: Int,
59         @ColorInt color1: Int,
60         @ColorInt color2: Int,
61         @ColorInt color3: Int,
62     ) {
63         this.color0 = color0
64         this.color1 = color1
65         this.color2 = color2
66         this.color3 = color3
67         invalidate()
68     }
69 
bindStrokeColornull70     fun bindStrokeColor(@ColorInt strokeColor: Int) {
71         this.strokeColor = strokeColor
72         invalidate()
73     }
74 
onSizeChangednull75     override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
76         this.w = w
77         this.h = h
78         super.onSizeChanged(w, h, oldw, oldh)
79     }
80 
onDrawnull81     override fun onDraw(canvas: Canvas) {
82         // The w and h need to be an even number to avoid tiny pixel-level gaps between the pies
83         w = w.roundDownToEven()
84         h = h.roundDownToEven()
85 
86         val width = w.toFloat()
87         val height = h.toFloat()
88 
89         val left = 2 * strokeWidth
90         val right = width - 2 * strokeWidth
91         val top = 2 * strokeWidth
92         val bottom = height - 2 * strokeWidth
93         val cornerRadius = ((right - left) / 2) * (1f - 0.25f * progress)
94         val save = canvas.save()
95         path.reset()
96         path.addRoundRect(left, top, right, bottom, cornerRadius, cornerRadius, Path.Direction.CW)
97         path.close()
98         canvas.clipPath(path)
99 
100         canvas.apply {
101             paint.style = Paint.Style.FILL
102             // top left
103             paint.color = color0
104             drawRect(0f, 0f, width / 2, height / 2, paint)
105             // top right
106             paint.color = color1
107             drawRect(width / 2, 0f, width, height / 2, paint)
108             // bottom left
109             paint.color = color2
110             drawRect(0f, height / 2, width / 2, height, paint)
111             // bottom right
112             paint.color = color3
113             drawRect(width / 2, height / 2, width, height, paint)
114         }
115 
116         canvas.restoreToCount(save)
117         paint.style = Paint.Style.STROKE
118         paint.color = strokeColor
119         paint.alpha = (255 * progress).toInt()
120         paint.strokeWidth = this.strokeWidth
121         val strokeCornerRadius = ((width - strokeWidth) / 2) * (1f - 0.25f * progress)
122         val halfStrokeWidth = 0.5f * strokeWidth
123         // Stroke is centered along the path, so account for half strokeWidth to stay within View
124         canvas.drawRoundRect(
125             halfStrokeWidth,
126             halfStrokeWidth,
127             width - halfStrokeWidth,
128             height - halfStrokeWidth,
129             strokeCornerRadius,
130             strokeCornerRadius,
131             paint,
132         )
133     }
134 
135     companion object {
136         const val DEFAULT_PLACEHOLDER_COLOR = Color.BLACK
137 
roundDownToEvennull138         fun Int.roundDownToEven(): Int {
139             return if (this % 2 == 0) this else this - 1
140         }
141     }
142 }
143