1 /* 2 * Copyright (C) 2022 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.systemui.shared.shadow 17 18 import android.content.Context 19 import android.content.res.Resources 20 import android.content.res.TypedArray 21 import android.graphics.Canvas 22 import android.util.AttributeSet 23 import android.widget.TextClock 24 import com.android.systemui.shared.R 25 import com.android.systemui.shared.shadow.DoubleShadowTextHelper.ShadowInfo 26 import com.android.systemui.shared.shadow.DoubleShadowTextHelper.applyShadows 27 import kotlin.math.floor 28 29 /** Extension of [TextClock] which draws two shadows on the text (ambient and key shadows) */ 30 class DoubleShadowTextClock 31 @JvmOverloads 32 constructor( 33 context: Context, 34 attrs: AttributeSet? = null, 35 defStyleAttr: Int = 0, 36 defStyleRes: Int = 0, 37 ) : TextClock(context, attrs, defStyleAttr, defStyleRes) { 38 private lateinit var mAmbientShadowInfo: ShadowInfo 39 private lateinit var mKeyShadowInfo: ShadowInfo 40 private var attributesInput: TypedArray? = null 41 private var resources: Resources? = null 42 43 constructor( 44 resources: Resources, 45 context: Context, 46 attrs: AttributeSet? = null, 47 defStyleAttr: Int = 0, 48 defStyleRes: Int = 0, 49 attributesInput: TypedArray? = null 50 ) : this(context, attrs, defStyleAttr, defStyleRes) { 51 this.attributesInput = attributesInput 52 this.resources = resources 53 this.initializeAttributes(attrs, defStyleAttr, defStyleRes) 54 } 55 init { 56 initializeAttributes(attrs, defStyleAttr, defStyleRes) 57 } 58 59 private fun initializeAttributes(attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) { 60 var attributes: TypedArray = 61 this.attributesInput 62 ?: context.obtainStyledAttributes( 63 attrs, 64 R.styleable.DoubleShadowTextClock, 65 defStyleAttr, 66 defStyleRes 67 ) 68 69 var resource: Resources = this.resources ?: context.resources 70 try { 71 val keyShadowBlur = 72 attributes.getDimensionPixelSize(R.styleable.DoubleShadowTextClock_keyShadowBlur, 0) 73 val keyShadowOffsetX = 74 attributes.getDimensionPixelSize( 75 R.styleable.DoubleShadowTextClock_keyShadowOffsetX, 76 0 77 ) 78 val keyShadowOffsetY = 79 attributes.getDimensionPixelSize( 80 R.styleable.DoubleShadowTextClock_keyShadowOffsetY, 81 0 82 ) 83 val keyShadowAlpha = 84 attributes.getFloat(R.styleable.DoubleShadowTextClock_keyShadowAlpha, 0f) 85 mKeyShadowInfo = 86 ShadowInfo( 87 keyShadowBlur.toFloat(), 88 keyShadowOffsetX.toFloat(), 89 keyShadowOffsetY.toFloat(), 90 keyShadowAlpha 91 ) 92 val ambientShadowBlur = 93 attributes.getDimensionPixelSize( 94 R.styleable.DoubleShadowTextClock_ambientShadowBlur, 95 0 96 ) 97 val ambientShadowOffsetX = 98 attributes.getDimensionPixelSize( 99 R.styleable.DoubleShadowTextClock_ambientShadowOffsetX, 100 0 101 ) 102 val ambientShadowOffsetY = 103 attributes.getDimensionPixelSize( 104 R.styleable.DoubleShadowTextClock_ambientShadowOffsetY, 105 0 106 ) 107 val ambientShadowAlpha = 108 attributes.getFloat(R.styleable.DoubleShadowTextClock_ambientShadowAlpha, 0f) 109 mAmbientShadowInfo = 110 ShadowInfo( 111 ambientShadowBlur.toFloat(), 112 ambientShadowOffsetX.toFloat(), 113 ambientShadowOffsetY.toFloat(), 114 ambientShadowAlpha 115 ) 116 val removeTextDescent = 117 attributes.getBoolean(R.styleable.DoubleShadowTextClock_removeTextDescent, false) 118 val textDescentExtraPadding = 119 attributes.getDimensionPixelSize( 120 R.styleable.DoubleShadowTextClock_textDescentExtraPadding, 121 0 122 ) 123 if (removeTextDescent) { 124 val addBottomPaddingToClock = 125 resource.getBoolean(R.bool.dream_overlay_complication_clock_bottom_padding) 126 val metrics = paint.fontMetrics 127 val padding = 128 if (addBottomPaddingToClock) { 129 textDescentExtraPadding + 130 floor(metrics.descent.toDouble()).toInt() / paddingDividedOffset 131 } else { 132 textDescentExtraPadding - floor(metrics.descent.toDouble()).toInt() 133 } 134 setPaddingRelative(0, 0, 0, padding) 135 } 136 } finally { 137 attributes.recycle() 138 } 139 } 140 141 companion object { 142 private val paddingDividedOffset = 2 143 } 144 145 public override fun onDraw(canvas: Canvas) { 146 applyShadows(mKeyShadowInfo, mAmbientShadowInfo, this, canvas) { super.onDraw(canvas) } 147 } 148 } 149