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
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,22 @@ import javax.inject.Singleton
/** A nanosecond timestamp */
@JvmInline
public value class TimestampNs constructor(public val value: Long) {
public operator fun minus(other: TimestampNs): DurationNs = DurationNs(value - other.value)
public inline operator fun minus(other: TimestampNs): DurationNs =
DurationNs(value - other.value)

public operator fun plus(other: DurationNs): TimestampNs = TimestampNs(value + other.value)
public inline operator fun plus(other: DurationNs): TimestampNs =
TimestampNs(value + other.value)
}

@JvmInline
public value class DurationNs(public val value: Long) {
public operator fun minus(other: DurationNs): DurationNs = DurationNs(value - other.value)
public inline operator fun minus(other: DurationNs): DurationNs =
DurationNs(value - other.value)

public operator fun plus(other: DurationNs): DurationNs = DurationNs(value + other.value)
public inline operator fun plus(other: DurationNs): DurationNs = DurationNs(value + other.value)

public operator fun plus(other: TimestampNs): TimestampNs = TimestampNs(value + other.value)
public inline operator fun plus(other: TimestampNs): TimestampNs =
TimestampNs(value + other.value)

public operator fun compareTo(other: DurationNs): Int {
return if (value == other.value) {
Expand All @@ -49,7 +53,7 @@ public value class DurationNs(public val value: Long) {
}

public companion object {
public fun fromMs(durationMs: Long): DurationNs = DurationNs(durationMs * 1_000_000L)
public inline fun fromMs(durationMs: Long): DurationNs = DurationNs(durationMs * 1_000_000L)
}
}

Expand All @@ -63,17 +67,18 @@ public class SystemTimeSource @Inject constructor() : TimeSource {
}

public object Timestamps {
public fun now(timeSource: TimeSource): TimestampNs = timeSource.now()
public inline fun now(timeSource: TimeSource): TimestampNs = timeSource.now()

public fun DurationNs.formatNs(): String = "$this ns"
public inline fun DurationNs.formatNs(): String = "$this ns"

public fun DurationNs.formatMs(decimals: Int = 3): String =
public inline fun DurationNs.formatMs(decimals: Int = 3): String =
"%.${decimals}f ms".format(null, this.value / 1_000_000.0)

public fun TimestampNs.formatNs(): String = "$this ns"
public inline fun TimestampNs.formatNs(): String = "$this ns"

public fun TimestampNs.formatMs(): String = "${this.value / 1_000_000} ms"
public inline fun TimestampNs.formatMs(): String = "${this.value / 1_000_000} ms"

public fun TimestampNs.measureNow(timeSource: TimeSource = SystemTimeSource()): DurationNs =
now(timeSource).minus(this)
public inline fun TimestampNs.measureNow(
timeSource: TimeSource = SystemTimeSource()
): DurationNs = now(timeSource) - this
}
3 changes: 2 additions & 1 deletion work/work-runtime/api/current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,9 @@ package androidx.work {
method @InaccessibleFromKotlin public java.util.Map<java.lang.String,java.lang.Object?> getKeyValueMap();
method public long getLong(String key, long defaultValue);
method public long[]? getLongArray(String key);
method public String?[]? getNullableStringArray(String key);
method public String? getString(String key);
method public String[]? getStringArray(String key);
method @Deprecated public String[]? getStringArray(String key);
method public <T> boolean hasKeyWithValueOfType(String key, Class<T> klass);
method public byte[] toByteArray();
property public java.util.Map<java.lang.String,java.lang.Object?> keyValueMap;
Expand Down
3 changes: 2 additions & 1 deletion work/work-runtime/api/restricted_current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,9 @@ package androidx.work {
method @InaccessibleFromKotlin public java.util.Map<java.lang.String,java.lang.Object?> getKeyValueMap();
method public long getLong(String key, long defaultValue);
method public long[]? getLongArray(String key);
method public String?[]? getNullableStringArray(String key);
method public String? getString(String key);
method public String[]? getStringArray(String key);
method @Deprecated public String[]? getStringArray(String key);
method public <T> boolean hasKeyWithValueOfType(String key, Class<T> klass);
method public byte[] toByteArray();
property public java.util.Map<java.lang.String,java.lang.Object?> keyValueMap;
Expand Down
59 changes: 59 additions & 0 deletions work/work-runtime/src/androidTest/java/androidx/work/DataTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ package androidx.work

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
Expand All @@ -47,4 +49,61 @@ class DataTest {
assertFalse(data.hasKeyWithValueOfType<Any>("nothing"))
assertFalse(data.hasKeyWithValueOfType<Float>("two"))
}

@Test
fun getNullableStringArray_withNullValues() {
val array = arrayOf("foo", null, "bar")
val data = workDataOf("array" to array)
val result = data.getNullableStringArray("array")
assertNotNull(result)
assertArrayEquals(array, result)
}

@Test
fun getNullableStringArray_noNullValues() {
val array = arrayOf("foo", "bar", "baz")
val data = workDataOf("array" to array)
val result = data.getNullableStringArray("array")
assertNotNull(result)
assertArrayEquals(array, result)
}

@Test
fun getNullableStringArray_allNulls() {
val array = arrayOf<String?>(null, null, null)
val data = workDataOf("array" to array)
val result = data.getNullableStringArray("array")
assertNotNull(result)
assertArrayEquals(array, result)
}

@Test
fun getNullableStringArray_emptyArray() {
val array = arrayOf<String?>()
val data = workDataOf("array" to array)
val result = data.getNullableStringArray("array")
assertNotNull(result)
assertArrayEquals(array, result)
}

@Test
fun getNullableStringArray_keyNotFound() {
val data = workDataOf()
val result = data.getNullableStringArray("nonexistent_key")
assertNull(result)
}

@Test
fun getNullableStringArray_wrongType() {
val data = workDataOf("array" to 123)
val result = data.getNullableStringArray("array")
assertNull(result)
}

@Test
fun getNullableStringArray_wrongArrayType() {
val data = workDataOf("array" to intArrayOf(1, 2, 3))
val result = data.getNullableStringArray("array")
assertNull(result)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ class WorkContinuationImplTestKt {
it.state == WorkInfo.State.SUCCEEDED
}
assertThat(info.outputData.size()).isEqualTo(2)
assertThat(info.outputData.getStringArray(stringTag)).isEqualTo(arrayOf("hello"))
assertThat(info.outputData.getNullableStringArray(stringTag))
.isEqualTo(arrayOf("hello"))
val intArray = info.outputData.getIntArray(intTag)!!.sortedArray()
assertThat(intArray).isEqualTo(intArrayOf(1, 3))
}
Expand Down
29 changes: 25 additions & 4 deletions work/work-runtime/src/main/java/androidx/work/Data_.kt
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,19 @@ public class Data {
return if (value is T) value else defaultValue
}

private inline fun <reified T : Any, TArray> getTypedArray(
private inline fun <reified T : Any?, TArray> getTypedArray(
key: String,
constructor: (size: Int, init: (index: Int) -> T) -> TArray,
): TArray? {
val value = values[key]
return if (value is Array<*> && value.isArrayOf<T>())
constructor(value.size) { i -> value[i] as T }
else null
if (value is Array<*>) {
try {
return constructor(value.size) { i -> value[i] as T }
} catch (e: ClassCastException) {
// Fall-through to return null if the cast fails
}
}
return null
}

/**
Expand Down Expand Up @@ -184,8 +189,24 @@ public class Data {
* @param key The key for the argument
* @return The value specified by the key if it exists; `null` otherwise
*/
@Deprecated(
message =
"Use getNullableStringArray(key) instead. This method does not correctly handle " +
"String arrays which may contain null elements.",
replaceWith = ReplaceWith("getNullableStringArray(key)"),
)
public fun getStringArray(key: String): Array<String>? = getTypedArray(key, ::Array)

/**
* Gets the string array value for the given key. The array may contain `null` elements.
*
* @param key The key for the argument
* @return The value specified by the key if it exists; `null` otherwise
*/
// null elements are supported to match the setter
@SuppressLint("NullableCollection", "NullableCollectionElement")
public fun getNullableStringArray(key: String): Array<String?>? = getTypedArray(key, ::Array)

public val keyValueMap: Map<String, Any?>
/**
* Gets all the values in this Data object.
Expand Down
6 changes: 5 additions & 1 deletion xr/compose/compose/api/current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ package androidx.xr.compose.subspace {
}

public final class SpatialColumnKt {
method @KotlinOnly @androidx.compose.runtime.Composable @androidx.xr.compose.subspace.SubspaceComposable public static void SpatialColumn(optional androidx.xr.compose.subspace.layout.SubspaceModifier modifier, optional androidx.xr.compose.subspace.layout.SpatialAlignment alignment, optional androidx.xr.compose.subspace.layout.SpatialArrangement.Vertical verticalArrangement, kotlin.jvm.functions.Function1<androidx.xr.compose.subspace.SpatialColumnScope,kotlin.Unit> content);
method @KotlinOnly @androidx.compose.runtime.Composable @androidx.xr.compose.subspace.SubspaceComposable public static inline void SpatialColumn(optional androidx.xr.compose.subspace.layout.SubspaceModifier modifier, optional androidx.xr.compose.subspace.layout.SpatialAlignment alignment, optional androidx.xr.compose.subspace.layout.SpatialArrangement.Vertical verticalArrangement, kotlin.jvm.functions.Function1<androidx.xr.compose.subspace.SpatialColumnScope,kotlin.Unit> content);
method @BytecodeOnly @androidx.compose.runtime.Composable @androidx.xr.compose.subspace.SubspaceComposable public static void SpatialColumn(androidx.xr.compose.subspace.layout.SubspaceModifier?, androidx.xr.compose.subspace.layout.SpatialAlignment?, androidx.xr.compose.subspace.layout.SpatialArrangement.Vertical?, kotlin.jvm.functions.Function3<? super androidx.xr.compose.subspace.SpatialColumnScope!,? super androidx.compose.runtime.Composer!,? super java.lang.Integer!,kotlin.Unit!>, androidx.compose.runtime.Composer?, int, int);
}

Expand Down Expand Up @@ -1036,7 +1036,9 @@ package androidx.xr.compose.subspace.layout {
method @KotlinOnly @androidx.compose.runtime.Composable @androidx.xr.compose.subspace.SubspaceComposable public static inline void SubspaceLayout(optional androidx.xr.compose.subspace.layout.SubspaceModifier modifier, androidx.xr.compose.subspace.layout.SubspaceMeasurePolicy measurePolicy);
method @BytecodeOnly @androidx.compose.runtime.Composable @androidx.xr.compose.subspace.SubspaceComposable public static void SubspaceLayout(androidx.xr.compose.subspace.layout.SubspaceModifier?, androidx.xr.compose.subspace.layout.SubspaceMeasurePolicy, androidx.compose.runtime.Composer?, int, int);
method @KotlinOnly @androidx.compose.runtime.Composable @androidx.xr.compose.subspace.SubspaceComposable public static inline void SubspaceLayout(kotlin.jvm.functions.Function0<kotlin.Unit> content, optional androidx.xr.compose.subspace.layout.SubspaceModifier modifier, androidx.xr.compose.subspace.layout.SubspaceMeasurePolicy measurePolicy);
method @KotlinOnly @androidx.compose.runtime.Composable @androidx.xr.compose.subspace.SubspaceComposable public static inline void SubspaceLayout(kotlin.jvm.functions.Function0<kotlin.Unit> content, String coreEntityName, optional androidx.xr.compose.subspace.layout.SubspaceModifier modifier, androidx.xr.compose.subspace.layout.SubspaceMeasurePolicy measurePolicy);
method @BytecodeOnly @androidx.compose.runtime.Composable @androidx.xr.compose.subspace.SubspaceComposable public static void SubspaceLayout(kotlin.jvm.functions.Function2<? super androidx.compose.runtime.Composer!,? super java.lang.Integer!,kotlin.Unit!>, androidx.xr.compose.subspace.layout.SubspaceModifier?, androidx.xr.compose.subspace.layout.SubspaceMeasurePolicy, androidx.compose.runtime.Composer?, int, int);
method @BytecodeOnly @androidx.compose.runtime.Composable @androidx.xr.compose.subspace.SubspaceComposable public static void SubspaceLayout(kotlin.jvm.functions.Function2<? super androidx.compose.runtime.Composer!,? super java.lang.Integer!,kotlin.Unit!>, String, androidx.xr.compose.subspace.layout.SubspaceModifier?, androidx.xr.compose.subspace.layout.SubspaceMeasurePolicy, androidx.compose.runtime.Composer?, int, int);
}

public interface SubspaceMeasurable {
Expand Down Expand Up @@ -1108,8 +1110,10 @@ package androidx.xr.compose.subspace.layout {
public abstract static class SubspacePlaceable.SubspacePlacementScope {
ctor public SubspacePlaceable.SubspacePlacementScope();
method @InaccessibleFromKotlin public androidx.xr.compose.subspace.layout.SubspaceLayoutCoordinates? getCoordinates();
method @InaccessibleFromKotlin protected abstract androidx.compose.ui.unit.LayoutDirection getParentLayoutDirection();
method public final void place(androidx.xr.compose.subspace.layout.SubspacePlaceable, androidx.xr.runtime.math.Pose pose);
property public androidx.xr.compose.subspace.layout.SubspaceLayoutCoordinates? coordinates;
property protected abstract androidx.compose.ui.unit.LayoutDirection parentLayoutDirection;
}

}
Expand Down
Loading
Loading