* main: (37 commits) Disable animations of instrumented tests (#1167) Bump gradle/wrapper-validation-action from 1 to 2 Remove unused release variable. Fixes #1231 Apply Composable Parameter Ordering Guidelines Remove kotlinx-coroutines-guava dependency from :sync:work Add explicit guava-android dependency for :sync:work Extract ScreenshotHelper to separate testing module Update AGP to 8.3.0 Remove Insert function - Insert is only used in test. - Upsert do same thing as Insert. 🤖 Updates baselines for Dependency Guard Bump the kotlin-ksp-compose group with 6 updates 🤖 Updates baselines for Dependency Guard Bump hilt from 2.50 to 2.51 Bump com.google.truth:truth from 1.1.5 to 1.4.2 Move java to kotlin folder. Remove disk usage testing Figuring out what is using 66Gb in the runner Dpm Improve converting to kotlin timezone Use trySend multiple times ... Change-Id: If3f564108d42675ba55ef242f0d06f04aff45c4apull/1230/head
commit
2d610b0775
@ -0,0 +1,6 @@
|
|||||||
|
// This file contains classes (with possible wildcards) that the Compose Compiler will treat as stable.
|
||||||
|
// It allows us to define classes that our not part of our codebase without wrapping them in a stable class.
|
||||||
|
// For more information, check https://developer.android.com/jetpack/compose/performance/stability/fix#configuration-file
|
||||||
|
|
||||||
|
java.time.ZoneId
|
||||||
|
java.time.ZoneOffset
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 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
|
||||||
|
*
|
||||||
|
* https://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.google.samples.apps.nowinandroid.core.data.test
|
||||||
|
|
||||||
|
import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
import kotlinx.datetime.TimeZone
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class DefaultZoneIdTimeZoneMonitor @Inject constructor() : TimeZoneMonitor {
|
||||||
|
override val currentTimeZone: Flow<TimeZone> = flowOf(TimeZone.of("Europe/Warsaw"))
|
||||||
|
}
|
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 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
|
||||||
|
*
|
||||||
|
* https://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.google.samples.apps.nowinandroid.core.data.util
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.os.Build.VERSION
|
||||||
|
import android.os.Build.VERSION_CODES
|
||||||
|
import androidx.tracing.trace
|
||||||
|
import com.google.samples.apps.nowinandroid.core.network.Dispatcher
|
||||||
|
import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers.IO
|
||||||
|
import com.google.samples.apps.nowinandroid.core.network.di.ApplicationScope
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
|
import kotlinx.coroutines.flow.conflate
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.flow.shareIn
|
||||||
|
import kotlinx.datetime.TimeZone
|
||||||
|
import kotlinx.datetime.toKotlinTimeZone
|
||||||
|
import java.time.ZoneId
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility for reporting current timezone the device has set.
|
||||||
|
* It always emits at least once with default setting and then for each TZ change.
|
||||||
|
*/
|
||||||
|
interface TimeZoneMonitor {
|
||||||
|
val currentTimeZone: Flow<TimeZone>
|
||||||
|
}
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
internal class TimeZoneBroadcastMonitor @Inject constructor(
|
||||||
|
@ApplicationContext private val context: Context,
|
||||||
|
@ApplicationScope appScope: CoroutineScope,
|
||||||
|
@Dispatcher(IO) private val ioDispatcher: CoroutineDispatcher,
|
||||||
|
) : TimeZoneMonitor {
|
||||||
|
|
||||||
|
override val currentTimeZone: SharedFlow<TimeZone> =
|
||||||
|
callbackFlow {
|
||||||
|
// Send the default time zone first.
|
||||||
|
trySend(TimeZone.currentSystemDefault())
|
||||||
|
|
||||||
|
// Registers BroadcastReceiver for the TimeZone changes
|
||||||
|
val receiver = object : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
if (intent.action != Intent.ACTION_TIMEZONE_CHANGED) return
|
||||||
|
|
||||||
|
val zoneIdFromIntent = if (VERSION.SDK_INT < VERSION_CODES.R) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
// Starting Android R we also get the new TimeZone.
|
||||||
|
intent.getStringExtra(Intent.EXTRA_TIMEZONE)?.let { timeZoneId ->
|
||||||
|
// We need to convert it from java.util.Timezone to java.time.ZoneId
|
||||||
|
val zoneId = ZoneId.of(timeZoneId, ZoneId.SHORT_IDS)
|
||||||
|
// Convert to kotlinx.datetime.TimeZone
|
||||||
|
zoneId.toKotlinTimeZone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there isn't a zoneId in the intent, fallback to the systemDefault, which should also reflect the change
|
||||||
|
trySend(zoneIdFromIntent ?: TimeZone.currentSystemDefault())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trace("TimeZoneBroadcastReceiver.register") {
|
||||||
|
context.registerReceiver(receiver, IntentFilter(Intent.ACTION_TIMEZONE_CHANGED))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send here again, because registering the Broadcast Receiver can take up to several milliseconds.
|
||||||
|
// This way, we can reduce the likelihood that a TZ change wouldn't be caught with the Broadcast Receiver.
|
||||||
|
trySend(TimeZone.currentSystemDefault())
|
||||||
|
|
||||||
|
awaitClose {
|
||||||
|
context.unregisterReceiver(receiver)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We use to prevent multiple emissions of the same type, because we use trySend multiple times.
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.conflate()
|
||||||
|
.flowOn(ioDispatcher)
|
||||||
|
// Sharing the callback to prevent multiple BroadcastReceivers being registered
|
||||||
|
.shareIn(appScope, SharingStarted.WhileSubscribed(5_000), 1)
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
/build
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 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
|
||||||
|
*
|
||||||
|
* https://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.
|
||||||
|
*/
|
||||||
|
plugins {
|
||||||
|
alias(libs.plugins.nowinandroid.android.library)
|
||||||
|
alias(libs.plugins.nowinandroid.android.library.compose)
|
||||||
|
alias(libs.plugins.nowinandroid.android.hilt)
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "com.google.samples.apps.nowinandroid.core.screenshottesting"
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api(libs.roborazzi)
|
||||||
|
implementation(libs.androidx.compose.ui.test)
|
||||||
|
implementation(libs.androidx.activity.compose)
|
||||||
|
implementation(libs.androidx.compose.ui.test)
|
||||||
|
implementation(libs.robolectric)
|
||||||
|
implementation(projects.core.common)
|
||||||
|
implementation(projects.core.designsystem)
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright 2022 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.
|
||||||
|
-->
|
||||||
|
<manifest />
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 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
|
||||||
|
*
|
||||||
|
* https://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.google.samples.apps.nowinandroid.core.testing.util
|
||||||
|
|
||||||
|
import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.datetime.TimeZone
|
||||||
|
|
||||||
|
class TestTimeZoneMonitor : TimeZoneMonitor {
|
||||||
|
|
||||||
|
private val timeZoneFlow = MutableStateFlow(defaultTimeZone)
|
||||||
|
|
||||||
|
override val currentTimeZone: Flow<TimeZone> = timeZoneFlow
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A test-only API to set the from tests.
|
||||||
|
*/
|
||||||
|
fun setTimeZone(zoneId: TimeZone) {
|
||||||
|
timeZoneFlow.value = zoneId
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val defaultTimeZone: TimeZone = TimeZone.of("Europe/Warsaw")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 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
|
||||||
|
*
|
||||||
|
* https://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.google.samples.apps.nowinandroid.core.ui
|
||||||
|
|
||||||
|
import androidx.compose.runtime.compositionLocalOf
|
||||||
|
import kotlinx.datetime.TimeZone
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TimeZone that can be provided with the TimeZoneMonitor.
|
||||||
|
* This way, it's not needed to pass every single composable the time zone to show in UI.
|
||||||
|
*/
|
||||||
|
val LocalTimeZone = compositionLocalOf { TimeZone.currentSystemDefault() }
|
@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022 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
|
|
||||||
*
|
|
||||||
* https://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.google.samples.apps.nowinandroid.core.ui
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.IntentFilter
|
|
||||||
|
|
||||||
class TimeZoneBroadcastReceiver(
|
|
||||||
val onTimeZoneChanged: () -> Unit,
|
|
||||||
) : BroadcastReceiver() {
|
|
||||||
private var registered = false
|
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
|
||||||
if (intent.action == Intent.ACTION_TIMEZONE_CHANGED) {
|
|
||||||
onTimeZoneChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun register(context: Context) {
|
|
||||||
if (!registered) {
|
|
||||||
val filter = IntentFilter()
|
|
||||||
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED)
|
|
||||||
context.registerReceiver(this, filter)
|
|
||||||
registered = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun unregister(context: Context) {
|
|
||||||
if (registered) {
|
|
||||||
context.unregisterReceiver(this)
|
|
||||||
registered = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in new issue