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