diff options
author | 2025-02-26 17:15:19 +0000 | |
---|---|---|
committer | 2025-03-05 16:40:32 +0000 | |
commit | 99e793a54d7c1897570c22fe84f55ca5b9c3dd61 (patch) | |
tree | 49095eaf66c5900d6936be781d8dad8f14055015 | |
parent | a2b57e1e4c756f3184f9150a7e36c55ee132f50a (diff) |
Reduce small object allocations by adding value version of RectF
Bug: 399835774
Test: Manually checked results
Flag: com.android.systemui.shared.clock_reactive_variants
Change-Id: I67ca17667e2f70121b7725080289beeb1d0831e5
13 files changed, 264 insertions, 121 deletions
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/CanvasUtil.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/CanvasUtil.kt index dd1599e5259d..9857d7f3d69d 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/CanvasUtil.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/CanvasUtil.kt @@ -17,6 +17,8 @@ package com.android.systemui.shared.clocks import android.graphics.Canvas +import com.android.systemui.plugins.clocks.VPoint +import com.android.systemui.plugins.clocks.VPointF object CanvasUtil { fun Canvas.translate(pt: VPointF) = this.translate(pt.x, pt.y) diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DigitTranslateAnimator.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DigitTranslateAnimator.kt index f5ccc52c8c6b..941cebfb4014 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DigitTranslateAnimator.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DigitTranslateAnimator.kt @@ -20,7 +20,8 @@ import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.animation.TimeInterpolator import android.animation.ValueAnimator -import com.android.systemui.shared.clocks.VPointF.Companion.times +import com.android.systemui.plugins.clocks.VPointF +import com.android.systemui.plugins.clocks.VPointF.Companion.times class DigitTranslateAnimator(private val updateCallback: (VPointF) -> Unit) { var currentTranslation = VPointF.ZERO diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt index 336c66eed889..9ac9e60f05fd 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt @@ -16,13 +16,13 @@ package com.android.systemui.shared.clocks -import android.graphics.RectF import android.view.View import androidx.annotation.VisibleForTesting import com.android.systemui.plugins.clocks.ClockAnimations import com.android.systemui.plugins.clocks.ClockEvents import com.android.systemui.plugins.clocks.ClockFaceConfig import com.android.systemui.plugins.clocks.ClockFaceEvents +import com.android.systemui.plugins.clocks.VRectF interface SimpleClockLayerController { val view: View @@ -32,5 +32,5 @@ interface SimpleClockLayerController { val config: ClockFaceConfig @VisibleForTesting var fakeTimeMills: Long? - var onViewBoundsChanged: ((RectF) -> Unit)? + var onViewBoundsChanged: ((VRectF) -> Unit)? } diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ViewUtils.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ViewUtils.kt index 1e90a2370786..0740b0e504cb 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ViewUtils.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ViewUtils.kt @@ -18,8 +18,9 @@ package com.android.systemui.shared.clocks import android.graphics.Rect import android.view.View -import com.android.systemui.shared.clocks.VPoint.Companion.center -import com.android.systemui.shared.clocks.VPointF.Companion.center +import com.android.systemui.plugins.clocks.VPoint.Companion.center +import com.android.systemui.plugins.clocks.VPointF +import com.android.systemui.plugins.clocks.VPointF.Companion.center object ViewUtils { fun View.computeLayoutDiff(targetRegion: Rect, isLargeClock: Boolean): VPointF { diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt index 2dc3e2b7af73..ba32ab083063 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt @@ -17,7 +17,6 @@ package com.android.systemui.shared.clocks.view import android.graphics.Canvas -import android.graphics.RectF import android.icu.text.NumberFormat import android.util.MathUtils.constrainedMap import android.view.View @@ -29,14 +28,15 @@ import com.android.app.animation.Interpolators import com.android.systemui.customization.R import com.android.systemui.plugins.clocks.ClockFontAxisSetting import com.android.systemui.plugins.clocks.ClockLogger +import com.android.systemui.plugins.clocks.VPoint +import com.android.systemui.plugins.clocks.VPointF +import com.android.systemui.plugins.clocks.VPointF.Companion.max +import com.android.systemui.plugins.clocks.VPointF.Companion.times +import com.android.systemui.plugins.clocks.VRectF import com.android.systemui.shared.clocks.CanvasUtil.translate import com.android.systemui.shared.clocks.CanvasUtil.use import com.android.systemui.shared.clocks.ClockContext import com.android.systemui.shared.clocks.DigitTranslateAnimator -import com.android.systemui.shared.clocks.VPoint -import com.android.systemui.shared.clocks.VPointF -import com.android.systemui.shared.clocks.VPointF.Companion.max -import com.android.systemui.shared.clocks.VPointF.Companion.times import com.android.systemui.shared.clocks.ViewUtils.measuredSize import java.util.Locale import kotlin.collections.filterNotNull @@ -101,7 +101,7 @@ class FlexClockView(clockCtx: ClockContext) : ViewGroup(clockCtx.context) { updateLocale(Locale.getDefault()) } - var onViewBoundsChanged: ((RectF) -> Unit)? = null + var onViewBoundsChanged: ((VRectF) -> Unit)? = null private val digitOffsets = mutableMapOf<Int, Float>() protected fun calculateSize( @@ -189,13 +189,7 @@ class FlexClockView(clockCtx: ClockContext) : ViewGroup(clockCtx.context) { fun updateLocation() { val layoutBounds = this.layoutBounds ?: return - val bounds = - RectF( - layoutBounds.centerX() - measuredWidth / 2f, - layoutBounds.centerY() - measuredHeight / 2f, - layoutBounds.centerX() + measuredWidth / 2f, - layoutBounds.centerY() + measuredHeight / 2f, - ) + val bounds = VRectF.fromCenter(layoutBounds.center, this.measuredSize) setFrame( bounds.left.roundToInt(), bounds.top.roundToInt(), @@ -215,16 +209,11 @@ class FlexClockView(clockCtx: ClockContext) : ViewGroup(clockCtx.context) { onAnimateDoze = null } - private val layoutBounds = RectF() + private var layoutBounds = VRectF.ZERO override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { logger.onLayout(changed, left, top, right, bottom) - - layoutBounds.left = left.toFloat() - layoutBounds.top = top.toFloat() - layoutBounds.right = right.toFloat() - layoutBounds.bottom = bottom.toFloat() - + layoutBounds = VRectF(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat()) updateChildFrames(isLayout = true) } diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt index 0ec2d188833a..5d5fa98a7ebc 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt @@ -23,7 +23,6 @@ import android.graphics.Paint import android.graphics.PorterDuff import android.graphics.PorterDuffXfermode import android.graphics.Rect -import android.graphics.RectF import android.os.VibrationEffect import android.text.Layout import android.text.TextPaint @@ -45,6 +44,10 @@ import com.android.systemui.plugins.clocks.ClockFontAxisSetting import com.android.systemui.plugins.clocks.ClockFontAxisSetting.Companion.replace import com.android.systemui.plugins.clocks.ClockFontAxisSetting.Companion.toFVar import com.android.systemui.plugins.clocks.ClockLogger +import com.android.systemui.plugins.clocks.VPoint +import com.android.systemui.plugins.clocks.VPointF +import com.android.systemui.plugins.clocks.VPointF.Companion.size +import com.android.systemui.plugins.clocks.VRectF import com.android.systemui.shared.Flags.ambientAod import com.android.systemui.shared.clocks.CanvasUtil.translate import com.android.systemui.shared.clocks.CanvasUtil.use @@ -53,9 +56,6 @@ import com.android.systemui.shared.clocks.DigitTranslateAnimator import com.android.systemui.shared.clocks.DimensionParser import com.android.systemui.shared.clocks.FLEX_CLOCK_ID import com.android.systemui.shared.clocks.FontTextStyle -import com.android.systemui.shared.clocks.VPoint -import com.android.systemui.shared.clocks.VPointF -import com.android.systemui.shared.clocks.VPointF.Companion.size import com.android.systemui.shared.clocks.ViewUtils.measuredSize import com.android.systemui.shared.clocks.ViewUtils.size import com.android.systemui.shared.clocks.toClockAxisSetting @@ -66,11 +66,11 @@ import kotlin.math.roundToInt private val TAG = SimpleDigitalClockTextView::class.simpleName!! -private fun Paint.getTextBounds(text: CharSequence, result: RectF = RectF()): RectF { - val rect = Rect() - this.getTextBounds(text, 0, text.length, rect) - result.set(rect) - return result +private val tempRect = Rect() + +private fun Paint.getTextBounds(text: CharSequence): VRectF { + this.getTextBounds(text, 0, text.length, tempRect) + return VRectF(tempRect) } enum class VerticalAlignment { @@ -143,7 +143,7 @@ open class SimpleDigitalClockTextView( fidgetFontVariation = buildFidgetVariation(lsFontAxes).toFVar() } - var onViewBoundsChanged: ((RectF) -> Unit)? = null + var onViewBoundsChanged: ((VRectF) -> Unit)? = null private val parser = DimensionParser(clockCtx.context) var maxSingleDigitHeight = -1f var maxSingleDigitWidth = -1f @@ -159,13 +159,13 @@ open class SimpleDigitalClockTextView( private val initThread = Thread.currentThread() // textBounds is the size of text in LS, which only measures current text in lockscreen style - var textBounds = RectF() + var textBounds = VRectF.ZERO // prevTextBounds and targetTextBounds are to deal with dozing animation between LS and AOD // especially for the textView which has different bounds during the animation // prevTextBounds holds the state we are transitioning from - private val prevTextBounds = RectF() + private var prevTextBounds = VRectF.ZERO // targetTextBounds holds the state we are interpolating to - private val targetTextBounds = RectF() + private var targetTextBounds = VRectF.ZERO protected val logger = ClockLogger(this, clockCtx.messageBuffer, this::class.simpleName!!) get() = field ?: ClockLogger.INIT_LOGGER @@ -215,8 +215,8 @@ open class SimpleDigitalClockTextView( lockScreenPaint.typeface = typefaceCache.getTypefaceForVariant(lsFontVariation) typeface = lockScreenPaint.typeface - lockScreenPaint.getTextBounds(text, textBounds) - targetTextBounds.set(textBounds) + textBounds = lockScreenPaint.getTextBounds(text) + targetTextBounds = textBounds textAnimator.setTextStyle(TextAnimator.Style(fVar = lsFontVariation)) measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED) @@ -287,7 +287,7 @@ open class SimpleDigitalClockTextView( canvas.use { digitTranslateAnimator?.apply { canvas.translate(currentTranslation) } canvas.translate(getDrawTranslation(interpBounds)) - if (isLayoutRtl()) canvas.translate(interpBounds.width() - textBounds.width(), 0f) + if (isLayoutRtl()) canvas.translate(interpBounds.width - textBounds.width, 0f) textAnimator.draw(canvas) } } @@ -302,16 +302,12 @@ open class SimpleDigitalClockTextView( super.setAlpha(alpha) } - private val layoutBounds = RectF() + private var layoutBounds = VRectF.ZERO override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { super.onLayout(changed, left, top, right, bottom) logger.onLayout(changed, left, top, right, bottom) - - layoutBounds.left = left.toFloat() - layoutBounds.top = top.toFloat() - layoutBounds.right = right.toFloat() - layoutBounds.bottom = bottom.toFloat() + layoutBounds = VRectF(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat()) } override fun invalidate() { @@ -408,10 +404,10 @@ open class SimpleDigitalClockTextView( } fun refreshText() { - lockScreenPaint.getTextBounds(text, textBounds) - if (this::textAnimator.isInitialized) { - textAnimator.textInterpolator.targetPaint.getTextBounds(text, targetTextBounds) - } + textBounds = lockScreenPaint.getTextBounds(text) + targetTextBounds = + if (!this::textAnimator.isInitialized) textBounds + else textAnimator.textInterpolator.targetPaint.getTextBounds(text) if (layout == null) { requestLayout() @@ -432,23 +428,23 @@ open class SimpleDigitalClockTextView( } /** Returns the interpolated text bounding rect based on interpolation progress */ - private fun getInterpolatedTextBounds(progress: Float = getInterpolatedProgress()): RectF { + private fun getInterpolatedTextBounds(progress: Float = getInterpolatedProgress()): VRectF { if (progress <= 0f) { return prevTextBounds } else if (!textAnimator.isRunning || progress >= 1f) { return targetTextBounds } - return RectF().apply { - left = lerp(prevTextBounds.left, targetTextBounds.left, progress) - right = lerp(prevTextBounds.right, targetTextBounds.right, progress) - top = lerp(prevTextBounds.top, targetTextBounds.top, progress) - bottom = lerp(prevTextBounds.bottom, targetTextBounds.bottom, progress) - } + return VRectF( + left = lerp(prevTextBounds.left, targetTextBounds.left, progress), + right = lerp(prevTextBounds.right, targetTextBounds.right, progress), + top = lerp(prevTextBounds.top, targetTextBounds.top, progress), + bottom = lerp(prevTextBounds.bottom, targetTextBounds.bottom, progress), + ) } private fun computeMeasuredSize( - interpBounds: RectF, + interpBounds: VRectF, widthMeasureSpec: Int = measuredWidthAndState, heightMeasureSpec: Int = measuredHeightAndState, ): VPointF { @@ -461,11 +457,11 @@ open class SimpleDigitalClockTextView( return VPointF( when { mode.x == EXACTLY -> MeasureSpec.getSize(widthMeasureSpec).toFloat() - else -> interpBounds.width() + 2 * lockScreenPaint.strokeWidth + else -> interpBounds.width + 2 * lockScreenPaint.strokeWidth }, when { mode.y == EXACTLY -> MeasureSpec.getSize(heightMeasureSpec).toFloat() - else -> interpBounds.height() + 2 * lockScreenPaint.strokeWidth + else -> interpBounds.height + 2 * lockScreenPaint.strokeWidth }, ) } @@ -489,44 +485,23 @@ open class SimpleDigitalClockTextView( } /** Set the location of the view to match the interpolated text bounds */ - private fun setInterpolatedLocation(measureSize: VPointF): RectF { - val targetRect = RectF() - targetRect.apply { - when (xAlignment) { - XAlignment.LEFT -> { - left = layoutBounds.left - right = layoutBounds.left + measureSize.x - } - XAlignment.CENTER -> { - left = layoutBounds.centerX() - measureSize.x / 2f - right = layoutBounds.centerX() + measureSize.x / 2f - } - XAlignment.RIGHT -> { - left = layoutBounds.right - measureSize.x - right = layoutBounds.right - } - } - - when (verticalAlignment) { - VerticalAlignment.TOP -> { - top = layoutBounds.top - bottom = layoutBounds.top + measureSize.y - } - VerticalAlignment.CENTER -> { - top = layoutBounds.centerY() - measureSize.y / 2f - bottom = layoutBounds.centerY() + measureSize.y / 2f - } - VerticalAlignment.BOTTOM -> { - top = layoutBounds.bottom - measureSize.y - bottom = layoutBounds.bottom - } - VerticalAlignment.BASELINE -> { - top = layoutBounds.centerY() - measureSize.y / 2f - bottom = layoutBounds.centerY() + measureSize.y / 2f - } - } - } + private fun setInterpolatedLocation(measureSize: VPointF): VRectF { + val pos = + VPointF( + when (xAlignment) { + XAlignment.LEFT -> layoutBounds.left + XAlignment.CENTER -> layoutBounds.center.x - measureSize.x / 2f + XAlignment.RIGHT -> layoutBounds.right - measureSize.x + }, + when (verticalAlignment) { + VerticalAlignment.TOP -> layoutBounds.top + VerticalAlignment.CENTER -> layoutBounds.center.y - measureSize.y / 2f + VerticalAlignment.BOTTOM -> layoutBounds.bottom - measureSize.y + VerticalAlignment.BASELINE -> layoutBounds.center.y - measureSize.y / 2f + }, + ) + val targetRect = VRectF.fromTopLeft(pos, measureSize) setFrame( targetRect.left.roundToInt(), targetRect.top.roundToInt(), @@ -537,7 +512,7 @@ open class SimpleDigitalClockTextView( return targetRect } - private fun getDrawTranslation(interpBounds: RectF): VPointF { + private fun getDrawTranslation(interpBounds: VRectF): VPointF { val sizeDiff = this.measuredSize - interpBounds.size val alignment = VPointF( @@ -586,11 +561,11 @@ open class SimpleDigitalClockTextView( if (fontSizePx > 0) { setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSizePx) lockScreenPaint.textSize = textSize - lockScreenPaint.getTextBounds(text, textBounds) - targetTextBounds.set(textBounds) + textBounds = lockScreenPaint.getTextBounds(text) + targetTextBounds = textBounds } if (!constrainedByHeight) { - val lastUnconstrainedHeight = textBounds.height() + lockScreenPaint.strokeWidth * 2 + val lastUnconstrainedHeight = textBounds.height + lockScreenPaint.strokeWidth * 2 fontSizeAdjustFactor = lastUnconstrainedHeight / lastUnconstrainedTextSize } @@ -608,8 +583,8 @@ open class SimpleDigitalClockTextView( for (i in 0..9) { val rectForCalculate = lockScreenPaint.getTextBounds("$i") - maxSingleDigitHeight = max(maxSingleDigitHeight, rectForCalculate.height()) - maxSingleDigitWidth = max(maxSingleDigitWidth, rectForCalculate.width()) + maxSingleDigitHeight = max(maxSingleDigitHeight, rectForCalculate.height) + maxSingleDigitWidth = max(maxSingleDigitWidth, rectForCalculate.width) } maxSingleDigitWidth += 2 * lockScreenPaint.strokeWidth maxSingleDigitHeight += 2 * lockScreenPaint.strokeWidth @@ -637,8 +612,8 @@ open class SimpleDigitalClockTextView( * and targetPaint will store the state we transition to */ private fun updateTextBoundsForTextAnimator() { - textAnimator.textInterpolator.basePaint.getTextBounds(text, prevTextBounds) - textAnimator.textInterpolator.targetPaint.getTextBounds(text, targetTextBounds) + prevTextBounds = textAnimator.textInterpolator.basePaint.getTextBounds(text) + targetTextBounds = textAnimator.textInterpolator.targetPaint.getTextBounds(text) } /** diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt index b52db83d513c..7657a2179d4f 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt @@ -13,7 +13,6 @@ */ package com.android.systemui.plugins.clocks -import android.graphics.RectF import com.android.systemui.plugins.annotations.ProtectedInterface import com.android.systemui.plugins.annotations.SimpleProperty import java.io.PrintWriter @@ -50,5 +49,5 @@ interface ClockController { } interface ClockEventListener { - fun onBoundsChanged(bounds: RectF) + fun onBoundsChanged(bounds: VRectF) } diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceEvents.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceEvents.kt index 20ee6c120ee8..a658c15a1a99 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceEvents.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceEvents.kt @@ -45,6 +45,7 @@ interface ClockFaceEvents { * render within the centered targetRect to avoid obstructing other elements. The specified * targetRegion is relative to the parent view. */ + @Deprecated("No longer necessary, pending removal") fun onTargetRegionChanged(targetRegion: Rect?) /** Called to notify the clock about its display. */ diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt index 02a3902a042c..6e967f12899e 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt @@ -16,7 +16,6 @@ package com.android.systemui.plugins.clocks -import android.graphics.Rect import android.view.View import android.view.View.MeasureSpec import com.android.systemui.log.core.LogLevel @@ -56,7 +55,10 @@ class ClockLogger(private val view: View?, buffer: MessageBuffer, tag: String) : } fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { - d({ "onLayout($bool1, ${Rect(int1, int2, long1.toInt(), long2.toInt())})" }) { + d({ + val rect = VRect(int1.toShort(), int2.toShort(), long1.toShort(), long2.toShort()) + "onLayout($bool1, $rect)" + }) { bool1 = changed int1 = left int2 = top diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/VPoint.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VPoint.kt index 3dae5305542b..6ec9bb45a917 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/VPoint.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VPoint.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.shared.clocks +package com.android.systemui.plugins.clocks import android.graphics.Point import android.graphics.PointF @@ -30,10 +30,10 @@ private val Y_MASK: ULong = 0x00000000FFFFFFFFU private fun unpackX(data: ULong): Int = ((data and X_MASK) shr 32).toInt() -private fun unpackY(data: ULong): Int = (data and Y_MASK).toInt() +private fun unpackY(data: ULong): Int = ((data and Y_MASK) shr 0).toInt() private fun pack(x: Int, y: Int): ULong { - return ((x.toULong() shl 32) and X_MASK) or (y.toULong() and Y_MASK) + return ((x.toULong() shl 32) and X_MASK) or ((y.toULong() shl 0) and Y_MASK) } @JvmInline @@ -44,8 +44,6 @@ value class VPointF(private val data: ULong) { val y: Float get() = Float.fromBits(unpackY(data)) - constructor() : this(0f, 0f) - constructor(pt: PointF) : this(pt.x, pt.y) constructor(x: Int, y: Int) : this(x.toFloat(), y.toFloat()) @@ -146,8 +144,6 @@ value class VPoint(private val data: ULong) { val y: Int get() = unpackY(data) - constructor() : this(0, 0) - constructor(x: Int, y: Int) : this(pack(x, y)) fun toPoint() = Point(x, y) diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VRect.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VRect.kt new file mode 100644 index 000000000000..8d8e3fbabc90 --- /dev/null +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VRect.kt @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2025 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.systemui.plugins.clocks + +import android.graphics.Rect +import android.graphics.RectF +import android.util.Half + +private val LEFT_MASK: ULong = 0xFFFF000000000000U +private val TOP_MASK: ULong = 0x0000FFFF00000000U +private val RIGHT_MASK: ULong = 0x00000000FFFF0000U +private val BOTTOM_MASK: ULong = 0x000000000000FFFFU + +private fun unpackLeft(data: ULong): Short = ((data and LEFT_MASK) shr 48).toShort() + +private fun unpackTop(data: ULong): Short = ((data and TOP_MASK) shr 32).toShort() + +private fun unpackRight(data: ULong): Short = ((data and RIGHT_MASK) shr 16).toShort() + +private fun unpackBottom(data: ULong): Short = ((data and BOTTOM_MASK) shr 0).toShort() + +private fun pack(left: Short, top: Short, right: Short, bottom: Short): ULong { + return ((left.toULong() shl 48) and LEFT_MASK) or + ((top.toULong() shl 32) and TOP_MASK) or + ((right.toULong() shl 16) and RIGHT_MASK) or + ((bottom.toULong() shl 0) and BOTTOM_MASK) +} + +@JvmInline +value class VRectF(private val data: ULong) { + val left: Float + get() = fromBits(unpackLeft(data)) + + val top: Float + get() = fromBits(unpackTop(data)) + + val right: Float + get() = fromBits(unpackRight(data)) + + val bottom: Float + get() = fromBits(unpackBottom(data)) + + val width: Float + get() = right - left + + val height: Float + get() = bottom - top + + constructor(rect: RectF) : this(rect.left, rect.top, rect.right, rect.bottom) + + constructor( + rect: Rect + ) : this( + left = rect.left.toFloat(), + top = rect.top.toFloat(), + right = rect.right.toFloat(), + bottom = rect.bottom.toFloat(), + ) + + constructor( + left: Float, + top: Float, + right: Float, + bottom: Float, + ) : this(pack(toBits(left), toBits(top), toBits(right), toBits(bottom))) + + val center: VPointF + get() = VPointF(left, top) + size / 2f + + val size: VPointF + get() = VPointF(width, height) + + override fun toString() = "($left, $top) -> ($right, $bottom)" + + companion object { + private fun toBits(value: Float): Short = Half.halfToShortBits(Half.toHalf(value)) + + private fun fromBits(value: Short): Float = Half.toFloat(Half.intBitsToHalf(value.toInt())) + + fun fromCenter(center: VPointF, size: VPointF): VRectF { + return VRectF( + center.x - size.x / 2, + center.y - size.y / 2, + center.x + size.x / 2, + center.y + size.y / 2, + ) + } + + fun fromTopLeft(pos: VPointF, size: VPointF): VRectF { + return VRectF(pos.x, pos.y, pos.x + size.x, pos.y + size.y) + } + + val ZERO = VRectF(0f, 0f, 0f, 0f) + } +} + +@JvmInline +value class VRect(private val data: ULong) { + val left: Int + get() = unpackLeft(data).toInt() + + val top: Int + get() = unpackTop(data).toInt() + + val right: Int + get() = unpackRight(data).toInt() + + val bottom: Int + get() = unpackBottom(data).toInt() + + val width: Int + get() = right - left + + val height: Int + get() = bottom - top + + constructor( + rect: Rect + ) : this( + left = rect.left.toShort(), + top = rect.top.toShort(), + right = rect.right.toShort(), + bottom = rect.bottom.toShort(), + ) + + constructor( + left: Short, + top: Short, + right: Short, + bottom: Short, + ) : this(pack(left, top, right, bottom)) + + val center: VPoint + get() = VPoint(left, top) + size / 2 + + val size: VPoint + get() = VPoint(width, height) + + override fun toString() = "($left, $top) -> ($right, $bottom)" + + companion object { + val ZERO = VRect(0, 0, 0, 0) + + fun fromCenter(center: VPoint, size: VPoint): VRect { + return VRect( + (center.x - size.x / 2).toShort(), + (center.y - size.y / 2).toShort(), + (center.x + size.x / 2).toShort(), + (center.y + size.y / 2).toShort(), + ) + } + + fun fromTopLeft(pos: VPoint, size: VPoint): VRect { + return VRect( + pos.x.toShort(), + pos.y.toShort(), + (pos.x + size.x).toShort(), + (pos.y + size.y).toShort(), + ) + } + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt index 1549b699eee6..763b1072f968 100644 --- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt @@ -21,7 +21,6 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.content.res.Resources -import android.graphics.RectF import android.os.Trace import android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS import android.provider.Settings.Global.ZEN_MODE_OFF @@ -60,6 +59,7 @@ import com.android.systemui.plugins.clocks.ClockEventListener import com.android.systemui.plugins.clocks.ClockFaceController import com.android.systemui.plugins.clocks.ClockMessageBuffers import com.android.systemui.plugins.clocks.ClockTickRate +import com.android.systemui.plugins.clocks.VRectF import com.android.systemui.plugins.clocks.WeatherData import com.android.systemui.plugins.clocks.ZenData import com.android.systemui.plugins.clocks.ZenData.ZenMode @@ -250,7 +250,7 @@ constructor( private var largeClockOnSecondaryDisplay = false val dozeAmount = MutableStateFlow(0f) - val onClockBoundsChanged = MutableStateFlow<RectF?>(null) + val onClockBoundsChanged = MutableStateFlow<VRectF>(VRectF.ZERO) private fun isDarkTheme(): Boolean { val isLightTheme = TypedValue() @@ -315,7 +315,7 @@ constructor( private val clockListener = object : ClockEventListener { - override fun onBoundsChanged(bounds: RectF) { + override fun onBoundsChanged(bounds: VRectF) { onClockBoundsChanged.value = bounds } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt index e81d5354ec6e..5ef2d6fd3256 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt @@ -29,6 +29,7 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.plugins.clocks.VRectF import com.android.systemui.res.R import com.android.systemui.shared.R as sharedR import kotlinx.coroutines.DisposableHandle @@ -135,7 +136,7 @@ object KeyguardSmartspaceViewBinder { } } - if (clockBounds == null) return@collect + if (clockBounds == VRectF.ZERO) return@collect if (isLargeClock) { val largeDateHeight = keyguardRootView |