Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions app/src/main/java/com/leanbitlab/lwidget/AwidgetProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,21 @@ class AwidgetProvider : AppWidgetProvider() {
}

companion object {

private var cachedLocale: java.util.Locale? = null
private val formatters = java.util.concurrent.ConcurrentHashMap<String, java.time.format.DateTimeFormatter>()

private fun getFormatter(pattern: String): java.time.format.DateTimeFormatter {
val currentLocale = java.util.Locale.getDefault()
if (cachedLocale != currentLocale) {
cachedLocale = currentLocale
formatters.clear()
}
return formatters.getOrPut(pattern) {
java.time.format.DateTimeFormatter.ofPattern(pattern, currentLocale)
}
}

const val ACTION_BATTERY_UPDATE = "com.leanbitlab.lwidget.ACTION_BATTERY_UPDATE"
const val PERMISSION_READ_TASKS_ORG = "org.tasks.permission.READ_TASKS"
const val PERMISSION_READ_TASKS_ASTRID = "com.todoroo.astrid.READ"
Expand Down Expand Up @@ -928,9 +943,9 @@ class AwidgetProvider : AppWidgetProvider() {
}

private fun bindCalendarEvents(context: Context, views: RemoteViews, events: List<EventInfo>, textSizeSp: Float, primaryColor: Int, secondaryColor: Int, eventViews: List<Int>) {
val timeFormatter = DateTimeFormatter.ofPattern("h:mm a", Locale.getDefault())
val dayFormatter = DateTimeFormatter.ofPattern("EEE", Locale.getDefault())
val dateFormatter = DateTimeFormatter.ofPattern("d MMM h:mma", Locale.getDefault())
val timeFormatter = getFormatter("h:mm a")
val dayFormatter = getFormatter("EEE")
val dateFormatter = getFormatter("d MMM h:mma")

if (events.isEmpty()) {
views.setTextViewText(eventViews[0], "No events today")
Expand Down Expand Up @@ -1157,7 +1172,7 @@ class AwidgetProvider : AppWidgetProvider() {
} else if (dueDate.isEqual(tomorrow)) {
" (Tomorrow)"
} else {
val df = DateTimeFormatter.ofPattern("MMM d", Locale.getDefault())
val df = getFormatter("MMM d")
" (${dueDate.format(df)})"
}
}
Expand Down Expand Up @@ -1222,7 +1237,7 @@ class AwidgetProvider : AppWidgetProvider() {
val zoneId = ZoneId.of(zoneIdStr)
val zdt = java.time.ZonedDateTime.now(zoneId)
val pattern = if (is12Hour) "h:mm a" else "H:mm"
val formatter = DateTimeFormatter.ofPattern(pattern, Locale.getDefault())
val formatter = getFormatter(pattern)
val timeStr = zdt.format(formatter)

// Format: "🌍 10:30 AM"
Expand All @@ -1243,7 +1258,7 @@ class AwidgetProvider : AppWidgetProvider() {

if (nextAlarm != null) {
val nextAlarmTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(nextAlarm.triggerTime), ZoneId.systemDefault())
val timeFormatter = DateTimeFormatter.ofPattern("h:mm a", Locale.getDefault())
val timeFormatter = getFormatter("h:mm a")
val timeText = nextAlarmTime.format(timeFormatter)

// Format: "| ⏰ 7:00 AM"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.leanbitlab.lwidget

import android.content.Context
import android.widget.RemoteViews
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment
import org.mockito.Mockito.mock
import kotlin.system.measureNanoTime
import java.time.format.DateTimeFormatter
import java.util.Locale

@RunWith(RobolectricTestRunner::class)
class AwidgetProviderBenchmarkTest {

@Test
fun benchmarkFormatterCreation() {
// Warmup
for (i in 0 until 100) {
DateTimeFormatter.ofPattern("h:mm a", Locale.getDefault())
}

val iterations = 10000
val timeNormal = measureNanoTime {
for (i in 0 until iterations) {
DateTimeFormatter.ofPattern("h:mm a", Locale.getDefault())
}
}

// Warmup Cached
val m = AwidgetProvider.Companion::class.java.getDeclaredMethod("getFormatter", String::class.java)
m.isAccessible = true
for (i in 0 until 100) {
m.invoke(AwidgetProvider.Companion, "h:mm a")
}

val timeCached = measureNanoTime {
for (i in 0 until iterations) {
m.invoke(AwidgetProvider.Companion, "h:mm a")
}
}

println("BENCHMARK_NORMAL: ${timeNormal / iterations} ns per call")
println("BENCHMARK_CACHED: ${timeCached / iterations} ns per call")
}
}
Loading