1 /* <lambda>null2 * 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 17 package com.android.systemui.battery.unified 18 19 import android.graphics.Canvas 20 import android.graphics.ColorFilter 21 import android.graphics.Paint 22 import android.graphics.PixelFormat 23 import android.graphics.Rect 24 import android.graphics.Typeface 25 import android.graphics.drawable.Drawable 26 import android.view.View 27 import com.android.systemui.battery.unified.BatteryLayersDrawable.Companion.Metrics 28 29 /** 30 * A variant of [BatteryPercentTextOnlyDrawable] with the following differences: 31 * 1. It is defined on a canvas of 12x10 (shortened by 6 points horizontally) 32 * 2. Because of this, we scale the font according to the number of characters 33 * 34 * Note that these drawing metrics are only tested to work with google-sans BOLD 35 */ 36 class BatterySpaceSharingPercentTextDrawable(font: Typeface) : Drawable() { 37 private var verticalNudge = 0f 38 private var hScale = 1f 39 private var vScale = 1f 40 41 // range 0-100 42 var batteryLevel: Int = 88 43 set(value) { 44 field = value 45 percentText = "$value" 46 invalidateSelf() 47 } 48 49 private var percentText = "$batteryLevel" 50 set(value) { 51 field = value 52 numberOfCharacters = percentText.length 53 } 54 55 private var numberOfCharacters = percentText.length 56 set(value) { 57 if (field != value) { 58 field = value 59 updateFontSize() 60 } 61 } 62 63 private val textPaint = 64 Paint().also { p -> 65 p.textSize = 10f 66 p.typeface = font 67 } 68 69 private fun updateFontSize() { 70 // These values are determined experimentally 71 when (numberOfCharacters) { 72 3 -> { 73 verticalNudge = 1f 74 textPaint.textSize = 6f * hScale 75 } 76 // 1, 2 77 else -> { 78 verticalNudge = 1.25f 79 textPaint.textSize = 9f * hScale 80 } 81 } 82 } 83 84 private fun updateScale() { 85 updateFontSize() 86 } 87 88 override fun onBoundsChange(bounds: Rect) { 89 super.onBoundsChange(bounds) 90 91 hScale = bounds.right / Metrics.ViewportWidth 92 vScale = bounds.bottom / Metrics.ViewportHeight 93 94 updateScale() 95 } 96 97 override fun draw(canvas: Canvas) { 98 val rtl = layoutDirection == View.LAYOUT_DIRECTION_RTL 99 val totalAvailableHeight = CanvasHeight * vScale 100 101 // Distribute the vertical whitespace around the text. This is a simplified version of 102 // the equation ((C - T) / 2) + T - V, where C == canvas height, T == text height, and V 103 // is the vertical nudge. 104 val offsetY = (totalAvailableHeight + textPaint.textSize) / 2 - (verticalNudge * vScale) 105 106 val totalAvailableWidth = CanvasWidth * hScale 107 val textWidth = textPaint.measureText(percentText) 108 val offsetX = (totalAvailableWidth - textWidth) / 2 109 110 canvas.drawText( 111 percentText, 112 ((if (rtl) ViewportInsetLeftRtl else ViewportInsetLeft) * hScale) + offsetX, 113 (ViewportInsetTop * vScale) + offsetY, 114 textPaint 115 ) 116 } 117 118 override fun setTint(tintColor: Int) { 119 textPaint.color = tintColor 120 super.setTint(tintColor) 121 } 122 123 override fun getOpacity() = PixelFormat.OPAQUE 124 125 override fun setAlpha(p0: Int) {} 126 127 override fun setColorFilter(colorFilter: ColorFilter?) { 128 textPaint.colorFilter = colorFilter 129 } 130 131 companion object { 132 private const val ViewportInsetLeft = 4f 133 private const val ViewportInsetLeftRtl = 2f 134 private const val ViewportInsetTop = 2f 135 136 private const val CanvasWidth = 12f 137 private const val CanvasHeight = 10f 138 } 139 } 140