diff options
5 files changed, 346 insertions, 197 deletions
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BlueprintAlignmentLines.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BlueprintAlignmentLines.kt new file mode 100644 index 000000000000..efa8cc7c2c55 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BlueprintAlignmentLines.kt @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2023 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.keyguard.ui.composable.blueprint + +import androidx.compose.ui.layout.HorizontalAlignmentLine +import androidx.compose.ui.layout.VerticalAlignmentLine +import kotlin.math.max +import kotlin.math.min + +/** + * Encapsulates all blueprint alignment lines. + * + * These can be used to communicate alignment lines emitted by elements that the blueprint should + * consume and use to know how to constrain and/or place other elements in that blueprint. + * + * For more information, please see + * [the official documentation](https://developer.android.com/jetpack/compose/layouts/alignment-lines). + */ +object BlueprintAlignmentLines { + + /** + * Encapsulates alignment lines produced by the lock icon element. + * + * Because the lock icon is also the same element as the under-display fingerprint sensor + * (UDFPS), blueprints should use its alignment lines to make sure that other elements on screen + * do not overlap with the lock icon. + */ + object LockIcon { + + /** The left edge of the lock icon. */ + val Left = + VerticalAlignmentLine( + merger = { old, new -> + // When two left alignment line values are provided, choose the leftmost one: + min(old, new) + }, + ) + + /** The top edge of the lock icon. */ + val Top = + HorizontalAlignmentLine( + merger = { old, new -> + // When two top alignment line values are provided, choose the topmost one: + min(old, new) + }, + ) + + /** The right edge of the lock icon. */ + val Right = + VerticalAlignmentLine( + merger = { old, new -> + // When two right alignment line values are provided, choose the rightmost one: + max(old, new) + }, + ) + + /** The bottom edge of the lock icon. */ + val Bottom = + HorizontalAlignmentLine( + merger = { old, new -> + // When two bottom alignment line values are provided, choose the bottommost + // one: + max(old, new) + }, + ) + } +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt index fc1df848d46f..7314453f089f 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt @@ -16,18 +16,13 @@ package com.android.systemui.keyguard.ui.composable.blueprint -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.offset import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.layout.Layout +import androidx.compose.ui.unit.IntRect import com.android.compose.animation.scene.SceneScope -import com.android.compose.modifiers.height -import com.android.compose.modifiers.width import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection import com.android.systemui.keyguard.ui.composable.section.ClockSection @@ -62,47 +57,104 @@ constructor( @Composable override fun SceneScope.Content(modifier: Modifier) { - val context = LocalContext.current - val lockIconBounds = lockSection.lockIconBounds(context) val isUdfpsVisible = viewModel.isUdfpsVisible - Box( - modifier = modifier, - ) { - Column( - modifier = Modifier.fillMaxWidth().height { lockIconBounds.top }, - ) { - with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) } - with(clockSection) { SmallClock(modifier = Modifier.fillMaxWidth()) } - with(smartSpaceSection) { SmartSpace(modifier = Modifier.fillMaxWidth()) } - with(clockSection) { LargeClock(modifier = Modifier.fillMaxWidth()) } - with(notificationSection) { - Notifications(modifier = Modifier.fillMaxWidth().weight(1f)) - } - if (!isUdfpsVisible) { - with(ambientIndicationSection) { - AmbientIndication(modifier = Modifier.fillMaxWidth()) + Layout( + content = { + // Constrained to above the lock icon. + Column( + modifier = Modifier.fillMaxWidth(), + ) { + with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) } + with(clockSection) { SmallClock(modifier = Modifier.fillMaxWidth()) } + with(smartSpaceSection) { SmartSpace(modifier = Modifier.fillMaxWidth()) } + with(clockSection) { LargeClock(modifier = Modifier.fillMaxWidth()) } + with(notificationSection) { + Notifications(modifier = Modifier.fillMaxWidth().weight(1f)) + } + if (!isUdfpsVisible) { + with(ambientIndicationSection) { + AmbientIndication(modifier = Modifier.fillMaxWidth()) + } } } - } - with(lockSection) { - LockIcon( - modifier = - Modifier.width { lockIconBounds.width() } - .height { lockIconBounds.height() } - .offset { IntOffset(lockIconBounds.left, lockIconBounds.top) } - ) - } + with(lockSection) { LockIcon() } - Column(modifier = Modifier.fillMaxWidth().align(Alignment.BottomCenter)) { - if (isUdfpsVisible) { - with(ambientIndicationSection) { - AmbientIndication(modifier = Modifier.fillMaxWidth()) + // Aligned to bottom and constrained to below the lock icon. + Column(modifier = Modifier.fillMaxWidth()) { + if (isUdfpsVisible) { + with(ambientIndicationSection) { + AmbientIndication(modifier = Modifier.fillMaxWidth()) + } } + + with(bottomAreaSection) { IndicationArea(modifier = Modifier.fillMaxWidth()) } } - with(bottomAreaSection) { BottomArea(modifier = Modifier.fillMaxWidth()) } + // Aligned to bottom and NOT constrained by the lock icon. + with(bottomAreaSection) { + Shortcut(isStart = true, applyPadding = true) + Shortcut(isStart = false, applyPadding = true) + } + }, + modifier = modifier, + ) { measurables, constraints -> + check(measurables.size == 5) + val ( + aboveLockIconMeasurable, + lockIconMeasurable, + belowLockIconMeasurable, + startShortcutMeasurable, + endShortcutMeasurable, + ) = measurables + + val noMinConstraints = + constraints.copy( + minWidth = 0, + minHeight = 0, + ) + val lockIconPlaceable = lockIconMeasurable.measure(noMinConstraints) + val lockIconBounds = + IntRect( + left = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Left], + top = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Top], + right = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Right], + bottom = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Bottom], + ) + + val aboveLockIconPlaceable = + aboveLockIconMeasurable.measure( + noMinConstraints.copy(maxHeight = lockIconBounds.top) + ) + val belowLockIconPlaceable = + belowLockIconMeasurable.measure( + noMinConstraints.copy(maxHeight = constraints.maxHeight - lockIconBounds.bottom) + ) + val startShortcutPleaceable = startShortcutMeasurable.measure(noMinConstraints) + val endShortcutPleaceable = endShortcutMeasurable.measure(noMinConstraints) + + layout(constraints.maxWidth, constraints.maxHeight) { + aboveLockIconPlaceable.place( + x = 0, + y = 0, + ) + lockIconPlaceable.place( + x = lockIconBounds.left, + y = lockIconBounds.top, + ) + belowLockIconPlaceable.place( + x = 0, + y = constraints.maxHeight - belowLockIconPlaceable.height, + ) + startShortcutPleaceable.place( + x = 0, + y = constraints.maxHeight - startShortcutPleaceable.height, + ) + endShortcutPleaceable.place( + x = constraints.maxWidth - endShortcutPleaceable.width, + y = constraints.maxHeight - endShortcutPleaceable.height, + ) } } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt index fa913f1695fe..4c119c7394bf 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt @@ -16,24 +16,13 @@ package com.android.systemui.keyguard.ui.composable.blueprint -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.heightIn -import androidx.compose.foundation.layout.offset -import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.layout.Layout +import androidx.compose.ui.unit.IntRect import com.android.compose.animation.scene.SceneScope -import com.android.compose.modifiers.height -import com.android.compose.modifiers.width import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection import com.android.systemui.keyguard.ui.composable.section.ClockSection @@ -42,12 +31,10 @@ import com.android.systemui.keyguard.ui.composable.section.NotificationSection import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection import com.android.systemui.keyguard.ui.composable.section.StatusBarSection import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel -import com.android.systemui.res.R import dagger.Binds import dagger.Module import dagger.multibindings.IntoSet import javax.inject.Inject -import kotlin.math.roundToInt /** * Renders the lockscreen scene when showing with the default layout (e.g. vertical phone form @@ -70,96 +57,107 @@ constructor( @Composable override fun SceneScope.Content(modifier: Modifier) { - val context = LocalContext.current - val lockIconBounds = lockSection.lockIconBounds(context) val isUdfpsVisible = viewModel.isUdfpsVisible - Box( - modifier = modifier, - ) { - Column( - modifier = Modifier.fillMaxWidth().height { lockIconBounds.top }, - ) { - with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) } - with(clockSection) { SmallClock(modifier = Modifier.fillMaxWidth()) } - with(smartSpaceSection) { SmartSpace(modifier = Modifier.fillMaxWidth()) } - with(clockSection) { LargeClock(modifier = Modifier.fillMaxWidth()) } - with(notificationSection) { - Notifications(modifier = Modifier.fillMaxWidth().weight(1f)) - } - if (!isUdfpsVisible) { - with(ambientIndicationSection) { - AmbientIndication(modifier = Modifier.fillMaxWidth()) + Layout( + content = { + // Constrained to above the lock icon. + Column( + modifier = Modifier.fillMaxWidth(), + ) { + with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) } + with(clockSection) { SmallClock(modifier = Modifier.fillMaxWidth()) } + with(smartSpaceSection) { SmartSpace(modifier = Modifier.fillMaxWidth()) } + with(clockSection) { LargeClock(modifier = Modifier.fillMaxWidth()) } + with(notificationSection) { + Notifications(modifier = Modifier.fillMaxWidth().weight(1f)) + } + if (!isUdfpsVisible) { + with(ambientIndicationSection) { + AmbientIndication(modifier = Modifier.fillMaxWidth()) + } } - } - } - - val shortcutSizePx = - with(LocalDensity.current) { bottomAreaSection.shortcutSizeDp().toSize() } - - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = - Modifier.fillMaxWidth().offset { - val rowTop = - if (shortcutSizePx.height > lockIconBounds.height()) { - (lockIconBounds.top - - (shortcutSizePx.height + lockIconBounds.height()) / 2) - .roundToInt() - } else { - lockIconBounds.top - } - - IntOffset(0, rowTop) - }, - ) { - Spacer(Modifier.weight(1f)) - - with(bottomAreaSection) { Shortcut(isStart = true) } - - Spacer(Modifier.weight(1f)) - - with(lockSection) { - LockIcon( - modifier = - Modifier.width { lockIconBounds.width() } - .height { lockIconBounds.height() } - ) } - Spacer(Modifier.weight(1f)) + // Constrained to the left of the lock icon (in left-to-right layouts). + with(bottomAreaSection) { Shortcut(isStart = true, applyPadding = false) } - with(bottomAreaSection) { Shortcut(isStart = false) } + with(lockSection) { LockIcon() } - Spacer(Modifier.weight(1f)) - } + // Constrained to the right of the lock icon (in left-to-right layouts). + with(bottomAreaSection) { Shortcut(isStart = false, applyPadding = false) } - Column(modifier = Modifier.fillMaxWidth().align(Alignment.BottomCenter)) { - if (isUdfpsVisible) { - with(ambientIndicationSection) { - AmbientIndication(modifier = Modifier.fillMaxWidth()) + // Aligned to bottom and constrained to below the lock icon. + Column(modifier = Modifier.fillMaxWidth()) { + if (isUdfpsVisible) { + with(ambientIndicationSection) { + AmbientIndication(modifier = Modifier.fillMaxWidth()) + } } - } - with(bottomAreaSection) { - IndicationArea( - modifier = - Modifier.fillMaxWidth() - .padding( - horizontal = - dimensionResource( - R.dimen.keyguard_affordance_horizontal_offset - ) - ) - .padding( - bottom = - dimensionResource( - R.dimen.keyguard_affordance_vertical_offset - ) - ) - .heightIn(min = shortcutSizeDp().height), - ) + with(bottomAreaSection) { IndicationArea(modifier = Modifier.fillMaxWidth()) } } + }, + modifier = modifier, + ) { measurables, constraints -> + check(measurables.size == 5) + val ( + aboveLockIconMeasurable, + startSideShortcutMeasurable, + lockIconMeasurable, + endSideShortcutMeasurable, + belowLockIconMeasurable, + ) = measurables + + val noMinConstraints = + constraints.copy( + minWidth = 0, + minHeight = 0, + ) + + val lockIconPlaceable = lockIconMeasurable.measure(noMinConstraints) + val lockIconBounds = + IntRect( + left = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Left], + top = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Top], + right = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Right], + bottom = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Bottom], + ) + + val aboveLockIconPlaceable = + aboveLockIconMeasurable.measure( + noMinConstraints.copy(maxHeight = lockIconBounds.top) + ) + val startSideShortcutPlaceable = startSideShortcutMeasurable.measure(noMinConstraints) + val endSideShortcutPlaceable = endSideShortcutMeasurable.measure(noMinConstraints) + val belowLockIconPlaceable = + belowLockIconMeasurable.measure( + noMinConstraints.copy(maxHeight = constraints.maxHeight - lockIconBounds.bottom) + ) + + layout(constraints.maxWidth, constraints.maxHeight) { + aboveLockIconPlaceable.place( + x = 0, + y = 0, + ) + startSideShortcutPlaceable.placeRelative( + x = lockIconBounds.left / 2 - startSideShortcutPlaceable.width / 2, + y = lockIconBounds.center.y - startSideShortcutPlaceable.height / 2, + ) + lockIconPlaceable.place( + x = lockIconBounds.left, + y = lockIconBounds.top, + ) + endSideShortcutPlaceable.placeRelative( + x = + lockIconBounds.right + (constraints.maxWidth - lockIconBounds.right) / 2 - + endSideShortcutPlaceable.width / 2, + y = lockIconBounds.center.y - endSideShortcutPlaceable.height / 2, + ) + belowLockIconPlaceable.place( + x = 0, + y = constraints.maxHeight - belowLockIconPlaceable.height, + ) } } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt index 53e4be34dcfa..db20f65ee78d 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.composable.section import android.view.View import android.widget.ImageView import androidx.annotation.IdRes -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -58,38 +57,17 @@ constructor( private val indicationAreaViewModel: KeyguardIndicationAreaViewModel, private val keyguardRootViewModel: KeyguardRootViewModel, ) { - @Composable - fun SceneScope.BottomArea( - modifier: Modifier = Modifier, - ) { - Row( - modifier = - modifier - .padding( - horizontal = - dimensionResource(R.dimen.keyguard_affordance_horizontal_offset) - ) - .padding( - bottom = dimensionResource(R.dimen.keyguard_affordance_vertical_offset) - ), - ) { - Shortcut( - isStart = true, - ) - - IndicationArea( - modifier = Modifier.weight(1f), - ) - - Shortcut( - isStart = false, - ) - } - } - + /** + * Renders a single lockscreen shortcut. + * + * @param isStart Whether the shortcut goes on the left (in left-to-right locales). + * @param applyPadding Whether to apply padding around the shortcut, this is needed if the + * shortcut is placed along the edges of the display. + */ @Composable fun SceneScope.Shortcut( isStart: Boolean, + applyPadding: Boolean, modifier: Modifier = Modifier, ) { MovableElement( @@ -103,6 +81,12 @@ constructor( falsingManager = falsingManager, vibratorHelper = vibratorHelper, indicationController = indicationController, + modifier = + if (applyPadding) { + Modifier.shortcutPadding() + } else { + Modifier + } ) } } @@ -113,7 +97,7 @@ constructor( ) { MovableElement( key = IndicationAreaElementKey, - modifier = modifier, + modifier = modifier.shortcutPadding(), ) { IndicationArea( indicationAreaViewModel = indicationAreaViewModel, @@ -218,6 +202,14 @@ constructor( modifier = modifier.fillMaxWidth(), ) } + + @Composable + private fun Modifier.shortcutPadding(): Modifier { + return this.padding( + horizontal = dimensionResource(R.dimen.keyguard_affordance_horizontal_offset) + ) + .padding(bottom = dimensionResource(R.dimen.keyguard_affordance_vertical_offset)) + } } private val StartButtonElementKey = ElementKey("StartButton") diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt index 8bbe424b9a49..d93863dd61e5 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt @@ -17,8 +17,6 @@ package com.android.systemui.keyguard.ui.composable.section import android.content.Context -import android.graphics.Point -import android.graphics.Rect import android.util.DisplayMetrics import android.view.WindowManager import androidx.compose.foundation.background @@ -28,11 +26,17 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.layout +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.Constraints +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.IntRect import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.SceneScope import com.android.systemui.biometrics.AuthController import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags +import com.android.systemui.keyguard.ui.composable.blueprint.BlueprintAlignmentLines import com.android.systemui.res.R import javax.inject.Inject @@ -49,8 +53,33 @@ constructor( key = LockIconElementKey, modifier = modifier, ) { + val context = LocalContext.current Box( - modifier = Modifier.background(Color.Red), + modifier = + Modifier.background(Color.Red).layout { measurable, _ -> + val lockIconBounds = lockIconBounds(context) + val placeable = + measurable.measure( + Constraints.fixed( + width = lockIconBounds.width, + height = lockIconBounds.height, + ) + ) + layout( + width = placeable.width, + height = placeable.height, + alignmentLines = + mapOf( + BlueprintAlignmentLines.LockIcon.Left to lockIconBounds.left, + BlueprintAlignmentLines.LockIcon.Top to lockIconBounds.top, + BlueprintAlignmentLines.LockIcon.Right to lockIconBounds.right, + BlueprintAlignmentLines.LockIcon.Bottom to + lockIconBounds.bottom, + ), + ) { + placeable.place(0, 0) + } + }, ) { Text( text = "TODO(b/316211368): Lock", @@ -67,9 +96,9 @@ constructor( * On devices that support UDFPS (under-display fingerprint sensor), the bounds of the icon are * the same as the bounds of the sensor. */ - fun lockIconBounds( + private fun lockIconBounds( context: Context, - ): Rect { + ): IntRect { val windowViewBounds = windowManager.currentWindowMetrics.bounds var widthPx = windowViewBounds.right.toFloat() if (featureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE)) { @@ -85,36 +114,33 @@ constructor( val lockIconRadiusPx = (defaultDensity * 36).toInt() val udfpsLocation = authController.udfpsLocation - return if (authController.isUdfpsSupported && udfpsLocation != null) { - centerLockIcon(udfpsLocation, authController.udfpsRadius) - } else { - val scaleFactor = authController.scaleFactor - val bottomPaddingPx = - context.resources.getDimensionPixelSize(R.dimen.lock_icon_margin_bottom) - val heightPx = windowViewBounds.bottom.toFloat() + val (center, radius) = + if (authController.isUdfpsSupported && udfpsLocation != null) { + Pair( + IntOffset( + x = udfpsLocation.x, + y = udfpsLocation.y, + ), + authController.udfpsRadius.toInt(), + ) + } else { + val scaleFactor = authController.scaleFactor + val bottomPaddingPx = + context.resources.getDimensionPixelSize(R.dimen.lock_icon_margin_bottom) + val heightPx = windowViewBounds.bottom.toFloat() - centerLockIcon( - Point( - (widthPx / 2).toInt(), - (heightPx - ((bottomPaddingPx + lockIconRadiusPx) * scaleFactor)).toInt() - ), - lockIconRadiusPx * scaleFactor - ) - } - } + Pair( + IntOffset( + x = (widthPx / 2).toInt(), + y = + (heightPx - ((bottomPaddingPx + lockIconRadiusPx) * scaleFactor)) + .toInt(), + ), + (lockIconRadiusPx * scaleFactor).toInt(), + ) + } - private fun centerLockIcon( - center: Point, - radius: Float, - ): Rect { - return Rect().apply { - set( - center.x - radius.toInt(), - center.y - radius.toInt(), - center.x + radius.toInt(), - center.y + radius.toInt(), - ) - } + return IntRect(center, radius) } } |