Extract out timer text specific utility from the dwb view

Bug: 405359383
Flag: com.android.launcher3.enable_refactor_digital_wellbeing_toast
Test: Unit test for the util
Change-Id: Ic7444e3e874e3b9870894cd16f7259f6fa1197c6
This commit is contained in:
Shamali P
2025-04-16 12:31:35 +00:00
committed by Shamali Patwa
parent 1ce7abb6fb
commit a7b69dc3d5
3 changed files with 150 additions and 37 deletions

View File

@@ -0,0 +1,60 @@
/*
* 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.quickstep.task.apptimer
import android.content.Context
import android.icu.text.MeasureFormat
import android.icu.util.Measure
import android.icu.util.MeasureUnit
import androidx.annotation.StringRes
import java.time.Duration
import java.util.Locale
/** Formats the given duration as a user friendly text. */
object DurationFormatter {
fun format(
context: Context,
duration: Duration,
@StringRes durationLessThanOneMinuteStringId: Int,
): String {
val hours = Math.toIntExact(duration.toHours())
val minutes = Math.toIntExact(duration.minusHours(hours.toLong()).toMinutes())
return when {
// Apply FormatWidth.NARROW if both the hour part and the minute part are non-zero.
hours > 0 && minutes > 0 ->
MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.NARROW)
.formatMeasures(
Measure(hours, MeasureUnit.HOUR),
Measure(minutes, MeasureUnit.MINUTE),
)
// Apply FormatWidth.WIDE if only the hour part is non-zero (unless forced).
hours > 0 ->
MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE)
.formatMeasures(Measure(hours, MeasureUnit.HOUR))
// Apply FormatWidth.WIDE if only the minute part is non-zero (unless forced).
minutes > 0 ->
MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE)
.formatMeasures(Measure(minutes, MeasureUnit.MINUTE))
// Use a specific string for usage less than one minute but non-zero.
duration > Duration.ZERO -> context.getString(durationLessThanOneMinuteStringId)
// Otherwise, return 0-minute string.
else ->
MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE)
.formatMeasures(Measure(0, MeasureUnit.MINUTE))
}
}
}

View File

@@ -24,9 +24,6 @@ import android.content.pm.LauncherApps
import android.content.pm.LauncherApps.AppUsageLimit
import android.graphics.Outline
import android.graphics.Paint
import android.icu.text.MeasureFormat
import android.icu.util.Measure
import android.icu.util.MeasureUnit
import android.os.UserHandle
import android.provider.Settings
import android.util.AttributeSet
@@ -35,7 +32,6 @@ import android.view.View
import android.view.ViewOutlineProvider
import android.view.accessibility.AccessibilityNodeInfo
import android.widget.TextView
import androidx.annotation.StringRes
import androidx.annotation.VisibleForTesting
import androidx.core.util.component1
import androidx.core.util.component2
@@ -47,10 +43,10 @@ import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_O
import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
import com.android.launcher3.util.SplitConfigurationOptions.StagePosition
import com.android.quickstep.TaskUtils
import com.android.quickstep.task.apptimer.DurationFormatter
import com.android.systemui.shared.recents.model.Task
import com.android.wm.shell.shared.split.SplitBounds
import java.time.Duration
import java.util.Locale
@SuppressLint("AppCompatCustomView")
class DigitalWellBeingToast
@@ -200,37 +196,6 @@ constructor(
}
}
private fun getReadableDuration(
duration: Duration,
@StringRes durationLessThanOneMinuteStringId: Int,
): String {
val hours = Math.toIntExact(duration.toHours())
val minutes = Math.toIntExact(duration.minusHours(hours.toLong()).toMinutes())
return when {
// Apply FormatWidth.WIDE if both the hour part and the minute part are non-zero.
hours > 0 && minutes > 0 ->
MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.NARROW)
.formatMeasures(
Measure(hours, MeasureUnit.HOUR),
Measure(minutes, MeasureUnit.MINUTE),
)
// Apply FormatWidth.WIDE if only the hour part is non-zero (unless forced).
hours > 0 ->
MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE)
.formatMeasures(Measure(hours, MeasureUnit.HOUR))
// Apply FormatWidth.WIDE if only the minute part is non-zero (unless forced).
minutes > 0 ->
MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE)
.formatMeasures(Measure(minutes, MeasureUnit.MINUTE))
// Use a specific string for usage less than one minute but non-zero.
duration > Duration.ZERO -> context.getString(durationLessThanOneMinuteStringId)
// Otherwise, return 0-minute string.
else ->
MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE)
.formatMeasures(Measure(0, MeasureUnit.MINUTE))
}
}
/**
* Returns text to show for the banner depending on [.getSplitBannerConfig] If {@param
* forContentDesc} is `true`, this will always return the full string corresponding to
@@ -249,7 +214,8 @@ constructor(
else remainingTime
)
val readableDuration =
getReadableDuration(
DurationFormatter.format(
context,
duration,
R.string.shorter_duration_less_than_one_minute, /* forceFormatWidth */
)