Merge "Import translations. DO NOT MERGE ANYWHERE" into androidx-main
diff --git a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/CameraControlAdapterDeviceTest.kt b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/CameraControlAdapterDeviceTest.kt
index 02bb86f..e5bccd9 100644
--- a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/CameraControlAdapterDeviceTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/CameraControlAdapterDeviceTest.kt
@@ -44,6 +44,7 @@
import androidx.camera.camera2.pipe.integration.interop.CaptureRequestOptions
import androidx.camera.camera2.pipe.integration.interop.ExperimentalCamera2Interop
import androidx.camera.camera2.pipe.testing.VerifyResultListener
+import androidx.camera.core.CameraControl
import androidx.camera.core.CameraSelector
import androidx.camera.core.FocusMeteringAction
import androidx.camera.core.ImageAnalysis
@@ -59,6 +60,8 @@
import androidx.test.filters.LargeTest
import androidx.test.filters.SdkSuppress
import com.google.common.truth.Truth
+import com.google.common.util.concurrent.ListenableFuture
+import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeUnit
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor
@@ -67,10 +70,10 @@
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.CoreMatchers.notNullValue
import org.junit.After
+import org.junit.Assert
import org.junit.Assume
import org.junit.Assume.assumeThat
import org.junit.Before
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -159,7 +162,6 @@
// TODO: test all public API of the CameraControl to ensure the RequestOptions still exist
// after adding/removing the UseCase.
- @Ignore("b/265316774")
@Test
fun removeUseCase_requestOptionsShouldSetToCamera(): Unit = runBlocking {
// Arrange.
@@ -338,12 +340,25 @@
)
}
+ @Test
+ fun setZoomRatio_operationCanceledExceptionIfNoUseCase() {
+ assertFutureFailedWithOperationCancellation(cameraControl.setZoomRatio(1.5f))
+ }
+
+ private fun <T> assertFutureFailedWithOperationCancellation(future: ListenableFuture<T>) {
+ Assert.assertThrows(ExecutionException::class.java) {
+ future[3, TimeUnit.SECONDS]
+ }.apply {
+ Truth.assertThat(cause)
+ .isInstanceOf(CameraControl.OperationCanceledException::class.java)
+ }
+ }
+
private fun CameraCharacteristics.getMaxRegionCount(
option_max_regions: CameraCharacteristics.Key<Int>
) = get(option_max_regions) ?: 0
private suspend fun arrangeRequestOptions() {
- cameraControl.setExposureCompensationIndex(1)
cameraControl.setZoomRatio(1.0f)
cameraControl.camera2cameraControl.setCaptureRequestOptions(
CaptureRequestOptions.Builder().setCaptureRequestOption(
@@ -351,6 +366,7 @@
CONTROL_CAPTURE_INTENT_CUSTOM
).build()
).await()
+ cameraControl.setExposureCompensationIndex(1)[5, TimeUnit.SECONDS]
// Ensure the requests are already set to the CaptureRequest.
waitForResult().verify(
@@ -420,4 +436,4 @@
)
cameraControl = camera.cameraControl as CameraControlAdapter
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/VerifyResultListener.kt b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/VerifyResultListener.kt
index 7469d0e..1c65179 100644
--- a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/VerifyResultListener.kt
+++ b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/VerifyResultListener.kt
@@ -68,8 +68,12 @@
signal.completeExceptionally(failureException)
return
}
- if (_verifyBlock(requestMetadata, result)) {
- signal.complete(Unit)
+ try {
+ if (_verifyBlock(requestMetadata, result)) {
+ signal.complete(Unit)
+ }
+ } catch (e: Throwable) {
+ signal.completeExceptionally(e)
}
}
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/UseCaseCameraConfig.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/UseCaseCameraConfig.kt
index f4ed9b6..b920ee1 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/UseCaseCameraConfig.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/UseCaseCameraConfig.kt
@@ -42,6 +42,7 @@
import dagger.Module
import dagger.Provides
import dagger.Subcomponent
+import java.util.concurrent.CancellationException
import javax.inject.Scope
@Scope
@@ -135,11 +136,15 @@
if (sessionConfigAdapter.isSessionConfigValid()) {
useCaseSurfaceManager.setupAsync(graph, sessionConfigAdapter, surfaceToStreamMap)
- .invokeOnCompletion {
- it?.let { Log.error(it) { "Surface setup error!" } }
+ .invokeOnCompletion { throwable ->
+ // Only show logs for error cases, ignore CancellationException since the task
+ // could be cancelled by UseCaseSurfaceManager#stopAsync().
+ if (throwable != null && throwable !is CancellationException) {
+ Log.error(throwable) { "Surface setup error!" }
+ }
}
} else {
- Log.debug {
+ Log.error {
"Unable to create capture session due to conflicting configurations"
}
}
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/FocusMeteringControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/FocusMeteringControl.kt
index 23f0b97..43b6750 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/FocusMeteringControl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/FocusMeteringControl.kt
@@ -32,7 +32,9 @@
import androidx.camera.core.FocusMeteringResult
import androidx.camera.core.MeteringPoint
import androidx.camera.core.Preview
+import androidx.camera.core.UseCase
import androidx.camera.core.impl.CameraControlInternal
+import androidx.lifecycle.Observer
import com.google.common.util.concurrent.ListenableFuture
import dagger.Binds
import dagger.Module
@@ -40,7 +42,10 @@
import javax.inject.Inject
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull
/**
@@ -53,20 +58,37 @@
val threads: UseCaseThreads,
) : UseCaseCameraControl {
private var _useCaseCamera: UseCaseCamera? = null
+
+ private val useCaseObserver = Observer<Set<UseCase>> { useCases ->
+ // reset to null since preview use case may not be active in current runningUseCases
+ previewAspectRatio = null
+ useCases.forEach { useCase ->
+ if (useCase is Preview) {
+ useCase.attachedSurfaceResolution?.apply {
+ previewAspectRatio = Rational(width, height)
+ }
+ }
+ }
+ }
+
override var useCaseCamera: UseCaseCamera?
get() = _useCaseCamera
set(value) {
+ if (_useCaseCamera != value) {
+ previewAspectRatio = null
+ // withContext does not switch thread properly with scope.launch so async is used
+ threads.sequentialScope.async {
+ withContext(Dispatchers.Main) {
+ _useCaseCamera?.runningUseCasesLiveData?.removeObserver(useCaseObserver)
+ }
+ }
+ }
+
_useCaseCamera = value
- // reset to null since preview ratio may not be applicable for current runningUseCases
- previewAspectRatio = null
- _useCaseCamera?.runningUseCasesLiveData?.observeForever { useCases ->
- useCases.forEach { useCase ->
- if (useCase is Preview) {
- useCase.attachedSurfaceResolution?.apply {
- previewAspectRatio = Rational(width, height)
- }
- }
+ threads.sequentialScope.async {
+ withContext(Dispatchers.Main) {
+ _useCaseCamera?.runningUseCasesLiveData?.observeForever(useCaseObserver)
}
}
}
@@ -75,6 +97,7 @@
cancelFocusAndMeteringAsync()
}
+ @Volatile
private var previewAspectRatio: Rational? = null
private val sensorRect by lazy {
// TODO("b/262225455"): use the actual crop sensor region like in camera-camera2
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
index f57b581..0826055 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
@@ -116,6 +116,11 @@
!attachedUseCases.contains(useCase)
}
+ // Notify state attached to use cases
+ for (useCase in unattachedUseCases) {
+ useCase.onStateAttached()
+ }
+
if (attachedUseCases.addAll(useCases)) {
if (shouldAddRepeatingUseCase(getRunningUseCases())) {
addRepeatingUseCase()
@@ -124,9 +129,9 @@
}
}
- // Notify state attached to use cases that weren't attached before
- for (useCase in unattachedUseCases) {
- useCase.onStateAttached()
+ unattachedUseCases.forEach { useCase ->
+ // Notify CameraControl is ready after the UseCaseCamera is created
+ useCase.onCameraControlReady()
}
}
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/ZoomControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/ZoomControl.kt
index 844552b..698da1b 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/ZoomControl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/ZoomControl.kt
@@ -21,7 +21,9 @@
import androidx.camera.camera2.pipe.integration.adapter.asListenableFuture
import androidx.camera.camera2.pipe.integration.compat.ZoomCompat
import androidx.camera.camera2.pipe.integration.config.CameraScope
+import androidx.camera.core.CameraControl
import androidx.camera.core.ZoomState
+import androidx.camera.core.impl.utils.futures.Futures
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.google.common.util.concurrent.ListenableFuture
@@ -117,17 +119,21 @@
fun setZoomRatioAsync(ratio: Float): ListenableFuture<Void> {
// TODO: report IllegalArgumentException if ratio not in range
- return threads.sequentialScope.launch(start = CoroutineStart.UNDISPATCHED) {
+ return Futures.nonCancellationPropagating(
useCaseCamera?.let {
- val zoomValue = ZoomValue(
- ratio,
- minZoom,
- maxZoom
- )
- setZoomState(zoomValue)
- update()
- }
- }.asListenableFuture()
+ threads.scope.launch(start = CoroutineStart.UNDISPATCHED) {
+ val zoomValue = ZoomValue(
+ ratio,
+ minZoom,
+ maxZoom
+ )
+ setZoomState(zoomValue)
+ update()
+ }.asListenableFuture()
+ } ?: Futures.immediateFailedFuture(
+ CameraControl.OperationCanceledException("Camera is not active.")
+ )
+ )
}
private fun nearZero(num: Float): Boolean {
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt
index 50afb50..2cb7051 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt
@@ -51,6 +51,7 @@
import androidx.camera.testing.fakes.FakeUseCase
import androidx.lifecycle.MutableLiveData
import androidx.test.filters.MediumTest
+import androidx.testutils.MainDispatcherRule
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import com.google.common.util.concurrent.FutureCallback
@@ -64,15 +65,22 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.asCoroutineDispatcher
+import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.async
+import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.withContext
+import org.junit.After
import org.junit.Assert.assertThrows
import org.junit.Before
import org.junit.Ignore
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.annotation.Config
@@ -101,11 +109,27 @@
SENSOR_WIDTH,
SENSOR_HEIGHT
)
+// the following rectangles are for metering point (0, 0)
+private val M_RECT_PVIEW_RATIO_16x9_SENSOR_640x480 = Rect(
+ 0, 60 - AREA_HEIGHT / 2,
+ AREA_WIDTH / 2, 60 + AREA_HEIGHT / 2
+)
+private val M_RECT_PVIEW_RATIO_4x3_SENSOR_1920x1080 = Rect(
+ 240 - AREA_WIDTH_2 / 2, 0,
+ 240 + AREA_WIDTH_2 / 2, AREA_HEIGHT_2 / 2
+)
+@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(RobolectricCameraPipeTestRunner::class)
@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
@DoNotInstrument
class FocusMeteringControlTest {
+ private val testScope = TestScope()
+ private val testDispatcher = StandardTestDispatcher(testScope.testScheduler)
+
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule(testDispatcher)
+
private val pointFactory = SurfaceOrientedMeteringPointFactory(1f, 1f)
private lateinit var focusMeteringControl: FocusMeteringControl
@@ -128,6 +152,15 @@
)
}
+ // testUseCaseThreads is used to ensure that all coroutines are executed before some specific
+ // point. But fakeUseCaseThreads can not be replaced in all tests because testDispatcher
+ // does not work well with withTimeoutOrNull()
+ private val testUseCaseThreads = UseCaseThreads(
+ testScope,
+ testDispatcher.asExecutor(),
+ testDispatcher
+ )
+
@Before
fun setUp() {
loadCameraProperties()
@@ -136,6 +169,18 @@
focusMeteringControl = initFocusMeteringControl(CAMERA_ID_0)
}
+ @After
+ fun tearDown() {
+ // CoroutineScope#cancel can throw exception if the scope has no job left
+ try {
+ // fakeUseCaseThreads may still be using Main dispatcher which sometimes
+ // causes Dispatchers.resetMain() to throw an exception:
+ // "IllegalStateException: Dispatchers.Main is used concurrently with setting it"
+ fakeUseCaseThreads.scope.cancel()
+ fakeUseCaseThreads.sequentialScope.cancel()
+ } catch (_: Exception) {}
+ }
+
@Test
fun meteringRegionsFromMeteringPoint_fovAspectRatioEqualToCropAspectRatio() {
val meteringPoint = FakeMeteringPointFactory().createPoint(0.0f, 0.0f)
@@ -389,17 +434,22 @@
// use 16:9 preview aspect ratio with sensor region of 4:3 (camera 0)
focusMeteringControl = initFocusMeteringControl(
CAMERA_ID_0,
- setOf(createPreview(Size(1920, 1080)))
+ setOf(createPreview(Size(1920, 1080))),
+ testUseCaseThreads,
)
+ testDispatcher.scheduler.advanceUntilIdle()
+
startFocusMeteringAndAwait(
FocusMeteringAction.Builder(point1).build()
)
- val adjustedRect = Rect(0, 60 - AREA_HEIGHT / 2, AREA_WIDTH / 2, 60 + AREA_HEIGHT / 2)
+ testDispatcher.scheduler.advanceUntilIdle()
+
with(fakeRequestControl.focusMeteringCalls.last()) {
assertWithMessage("Wrong number of AF regions").that(afRegions.size).isEqualTo(1)
- assertWithMessage("Wrong AF region").that(afRegions[0].rect).isEqualTo(adjustedRect)
+ assertWithMessage("Wrong AF region")
+ .that(afRegions[0].rect).isEqualTo(M_RECT_PVIEW_RATIO_16x9_SENSOR_640x480)
}
}
@@ -408,20 +458,22 @@
// use 4:3 preview aspect ratio with sensor region of 16:9 (camera 1)
focusMeteringControl = initFocusMeteringControl(
CAMERA_ID_1,
- setOf(createPreview(Size(640, 480)))
+ setOf(createPreview(Size(640, 480))),
+ testUseCaseThreads,
)
+ testDispatcher.scheduler.advanceUntilIdle()
+
startFocusMeteringAndAwait(
FocusMeteringAction.Builder(point1).build()
)
- val adjustedRect = Rect(
- 240 - AREA_WIDTH_2 / 2, 0,
- 240 + AREA_WIDTH_2 / 2, AREA_HEIGHT_2 / 2
- )
+ testDispatcher.scheduler.advanceUntilIdle()
+
with(fakeRequestControl.focusMeteringCalls.last()) {
assertWithMessage("Wrong number of AF regions").that(afRegions.size).isEqualTo(1)
- assertWithMessage("Wrong AF region").that(afRegions[0].rect).isEqualTo(adjustedRect)
+ assertWithMessage("Wrong AF region")
+ .that(afRegions[0].rect).isEqualTo(M_RECT_PVIEW_RATIO_4x3_SENSOR_1920x1080)
}
}
@@ -436,17 +488,22 @@
focusMeteringControl = initFocusMeteringControl(
CAMERA_ID_0,
- setOf(createPreview(Size(640, 480)))
+ setOf(createPreview(Size(640, 480))),
+ testUseCaseThreads,
)
+ testDispatcher.scheduler.advanceUntilIdle()
+
startFocusMeteringAndAwait(
FocusMeteringAction.Builder(point).build()
)
- val adjustedRect = Rect(0, 60 - AREA_HEIGHT / 2, AREA_WIDTH / 2, 60 + AREA_HEIGHT / 2)
+ testDispatcher.scheduler.advanceUntilIdle()
+
with(fakeRequestControl.focusMeteringCalls.last()) {
assertWithMessage("Wrong number of AF regions").that(afRegions.size).isEqualTo(1)
- assertWithMessage("Wrong AF region").that(afRegions[0].rect).isEqualTo(adjustedRect)
+ assertWithMessage("Wrong AF region")
+ .that(afRegions[0].rect).isEqualTo(M_RECT_PVIEW_RATIO_16x9_SENSOR_640x480)
}
}
@@ -455,18 +512,57 @@
// add 16:9 aspect ratio Preview with sensor region of 4:3 (camera 0), then remove Preview
focusMeteringControl = initFocusMeteringControl(
CAMERA_ID_0,
- setOf(createPreview(Size(1920, 1080)))
+ setOf(createPreview(Size(1920, 1080))),
+ testUseCaseThreads,
)
fakeUseCaseCamera.runningUseCasesLiveData.value = emptySet()
+ testDispatcher.scheduler.advanceUntilIdle()
+
startFocusMeteringAndAwait(
FocusMeteringAction.Builder(point1).build()
)
- val adjustedRect = Rect(0, 60 - AREA_HEIGHT / 2, AREA_WIDTH / 2, 60 + AREA_HEIGHT / 2)
+ testDispatcher.scheduler.advanceUntilIdle()
+
+ // point1 = (0, 0) is considered as center point of metering rectangle.
+ // Since previewAspectRatio is not set, it will be same as cropRegionAspectRatio
+ // which is the size of SENSOR_1 in this test. So the point is not adjusted,
+ // and simply M_RECT_1 (metering rectangle of point1 with SENSOR_1) should be used.
with(fakeRequestControl.focusMeteringCalls.last()) {
assertWithMessage("Wrong number of AF regions").that(afRegions.size).isEqualTo(1)
- assertWithMessage("Wrong AF region").that(afRegions[0].rect).isEqualTo(adjustedRect)
+ assertWithMessage("Wrong AF region").that(afRegions[0].rect).isEqualTo(M_RECT_1)
+ }
+ }
+
+ @Test
+ fun previewRatioIsNotChanged_whenSameUseCaseCameraSetTwice() {
+ // use 16:9 aspect ratio Preview with sensor region of 4:3 (camera 0)
+ val useCases = setOf<UseCase>(createPreview(Size(1920, 1080)))
+
+ focusMeteringControl = initFocusMeteringControl(
+ CAMERA_ID_0,
+ useCases,
+ UseCaseThreads(
+ testScope,
+ testDispatcher.asExecutor(),
+ testDispatcher
+ ),
+ )
+ focusMeteringControl.useCaseCamera = fakeUseCaseCamera
+
+ testDispatcher.scheduler.advanceUntilIdle()
+
+ startFocusMeteringAndAwait(
+ FocusMeteringAction.Builder(point1).build()
+ )
+
+ testDispatcher.scheduler.advanceUntilIdle()
+
+ with(fakeRequestControl.focusMeteringCalls.last()) {
+ assertWithMessage("Wrong number of AF regions").that(afRegions.size).isEqualTo(1)
+ assertWithMessage("Wrong AF region")
+ .that(afRegions[0].rect).isEqualTo(M_RECT_PVIEW_RATIO_16x9_SENSOR_640x480)
}
}
@@ -1035,8 +1131,9 @@
private fun initFocusMeteringControl(
cameraId: String,
useCases: Set<UseCase> = emptySet(),
+ useCaseThreads: UseCaseThreads = fakeUseCaseThreads,
) = FocusMeteringControl(
- cameraPropertiesMap[cameraId]!!, fakeUseCaseThreads
+ cameraPropertiesMap[cameraId]!!, useCaseThreads
).apply {
fakeUseCaseCamera.runningUseCasesLiveData.value = useCases
useCaseCamera = fakeUseCaseCamera
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
index 5c049d2..db443b2 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
@@ -692,7 +692,7 @@
* use count to recover the additional increment here.
*/
mCameraControlInternal.incrementUseCount();
- notifyStateAttachedToUseCases(new ArrayList<>(useCases));
+ notifyStateAttachedAndCameraControlReady(new ArrayList<>(useCases));
List<UseCaseInfo> useCaseInfos = new ArrayList<>(toUseCaseInfos(useCases));
try {
mExecutor.execute(() -> {
@@ -798,7 +798,7 @@
return mCameraConfig;
}
- private void notifyStateAttachedToUseCases(List<UseCase> useCases) {
+ private void notifyStateAttachedAndCameraControlReady(List<UseCase> useCases) {
for (UseCase useCase : useCases) {
String useCaseId = getUseCaseId(useCase);
if (mNotifyStateAttachedSet.contains(useCaseId)) {
@@ -807,6 +807,7 @@
mNotifyStateAttachedSet.add(useCaseId);
useCase.onStateAttached();
+ useCase.onCameraControlReady();
}
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
index 2e91175..d23ff83 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
@@ -616,7 +616,7 @@
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@Override
- protected void onCameraControlReady() {
+ public void onCameraControlReady() {
trySetFlashModeToCameraControl();
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java b/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java
index 613a40c..165bcba 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java
@@ -564,7 +564,7 @@
* @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
- protected void onCameraControlReady() {
+ public void onCameraControlReady() {
}
/**
@@ -695,15 +695,11 @@
* session with the use case session config. The use case can receive the frame data from the
* camera after the capture session is configured.
*
- * <p>The {@link CameraControlInternal} retrieved by {@link #getCameraControl()} is ready to
- * use after this callback function is invoked.
- *
* @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@CallSuper
public void onStateAttached() {
- onCameraControlReady();
}
/**
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
index f97ec40..3d75d57 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
@@ -60,9 +60,11 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* A {@link CameraInternal} adapter which checks that the UseCases to make sure that the resolutions
@@ -85,10 +87,12 @@
private final CameraId mId;
- // This includes app provided use cases and the extra placeholder use cases (mExtraUseCases)
- // created by CameraX.
+ // UseCases from the app. This does not include internal UseCases created by CameraX.
@GuardedBy("mLock")
- private final List<UseCase> mUseCases = new ArrayList<>();
+ private final Set<UseCase> mUseCases = new HashSet<>();
+ // UseCases sent to the camera including internal UseCases created by CameraX.
+ @GuardedBy("mLock")
+ private final Set<UseCase> mCameraUseCases = new HashSet<>();
@GuardedBy("mLock")
@Nullable
@@ -114,9 +118,11 @@
@GuardedBy("mLock")
private Config mInteropConfig = null;
- // The extra placeholder use cases created by CameraX to make sure the camera can work normally.
+ // The placeholder UseCase created to meet combination criteria for Extensions. e.g. When
+ // Extensions require both Preview and ImageCapture and app only provides one of them,
+ // CameraX will create the other and track it with this variable.
@GuardedBy("mLock")
- private List<UseCase> mExtraUseCases = new ArrayList<>();
+ private UseCase mPlaceholderForExtensions;
/**
* Create a new {@link CameraUseCaseAdapter} instance.
@@ -186,124 +192,110 @@
* @throws CameraException Thrown if the combination of newly added UseCases and the
* currently added UseCases exceed the capability of the camera.
*/
- public void addUseCases(@NonNull Collection<UseCase> useCases) throws CameraException {
+ public void addUseCases(@NonNull Collection<UseCase> appUseCasesToAdd) throws CameraException {
synchronized (mLock) {
- // TODO: merge UseCase for stream sharing. e.g. replace Preview and VideoCapture with a
- // StreamSharing UseCase.
- List<UseCase> newUseCases = new ArrayList<>();
- for (UseCase useCase : useCases) {
- if (mUseCases.contains(useCase)) {
- Logger.d(TAG, "Attempting to attach already attached UseCase");
- } else {
- newUseCases.add(useCase);
- }
- }
-
- List<UseCase> allUseCases = new ArrayList<>(mUseCases);
- List<UseCase> requiredExtraUseCases = emptyList();
- List<UseCase> removedExtraUseCases = emptyList();
-
- if (isCoexistingPreviewImageCaptureRequired()) {
- // Collects all use cases that will be finally bound by the application
- allUseCases.removeAll(mExtraUseCases);
- allUseCases.addAll(newUseCases);
-
- // Calculates the required extra use cases according to the use cases finally bound
- // by the application and the existing extra use cases.
- requiredExtraUseCases = calculateRequiredExtraUseCases(allUseCases,
- new ArrayList<>(mExtraUseCases));
-
- // Calculates the new added extra use cases
- List<UseCase> addedExtraUseCases = new ArrayList<>(requiredExtraUseCases);
- addedExtraUseCases.removeAll(mExtraUseCases);
-
- // Adds the new added extra use cases to the newUseCases list
- newUseCases.addAll(addedExtraUseCases);
-
- // Calculates the removed extra use cases
- removedExtraUseCases = new ArrayList<>(mExtraUseCases);
- removedExtraUseCases.removeAll(requiredExtraUseCases);
- }
-
- Map<UseCase, ConfigPair> configs = getConfigs(newUseCases,
- mCameraConfig.getUseCaseConfigFactory(), mUseCaseConfigFactory);
-
- Map<UseCase, Size> suggestedResolutionsMap;
+ Set<UseCase> appUseCasesAfter = new HashSet<>(mUseCases);
+ appUseCasesAfter.addAll(appUseCasesToAdd);
try {
- // Removes the unnecessary extra use cases and then checks whether all uses cases
- // including all the use cases finally bound by the application and the needed
- // extra use cases can be supported by guaranteed supported configurations tables.
- List<UseCase> boundUseCases = new ArrayList<>(mUseCases);
- boundUseCases.removeAll(removedExtraUseCases);
- suggestedResolutionsMap =
- calculateSuggestedResolutions(mCameraInternal.getCameraInfoInternal(),
- newUseCases, boundUseCases, configs);
+ updateUseCases(appUseCasesAfter);
} catch (IllegalArgumentException e) {
throw new CameraException(e.getMessage());
}
- updateViewPort(suggestedResolutionsMap, useCases);
- updateEffects(mEffects, useCases);
- // Saves the updated extra use cases set after confirming the use case combination
- // can be supported.
- mExtraUseCases = requiredExtraUseCases;
-
- // Detaches the unnecessary existing extra use cases
- detachUnnecessaryUseCases(removedExtraUseCases);
-
- // At this point the binding will succeed since all the calculations are done
- // Do all attaching related work
- for (UseCase useCase : newUseCases) {
- ConfigPair configPair = configs.get(useCase);
- useCase.bindToCamera(mCameraInternal, configPair.mExtendedConfig,
- configPair.mCameraConfig);
- useCase.updateSuggestedResolution(
- Preconditions.checkNotNull(suggestedResolutionsMap.get(useCase)));
- }
-
- // The added use cases will include the app provided use cases and the new added extra
- // use cases.
- mUseCases.addAll(newUseCases);
- if (mAttached) {
- mCameraInternal.attachUseCases(newUseCases);
- }
-
- // Once all use cases are attached, they need to notify the CameraInternal of its state
- for (UseCase useCase : newUseCases) {
- useCase.notifyState();
- }
}
}
/**
* Remove the specified collection of {@link UseCase} from the adapter.
*/
- public void removeUseCases(@NonNull Collection<UseCase> useCases) {
+ public void removeUseCases(@NonNull Collection<UseCase> useCasesToRemove) {
synchronized (mLock) {
- detachUnnecessaryUseCases(new ArrayList<>(useCases));
-
- // Calls addUseCases() function to calculate and add extra use cases if coexisting
- // Preview and ImageCapture are required.
- if (isCoexistingPreviewImageCaptureRequired()) {
- // The useCases might include extra use cases when unbinding all use cases.
- // Removes the unbound extra use cases from mExtraUseCases.
- mExtraUseCases.removeAll(useCases);
-
- try {
- // Calls addUseCases with empty list to add required extra fake use case.
- addUseCases(emptyList());
- } catch (CameraException e) {
- // This should not happen because the extra fake use case should be only
- // added to replace the removed one which the use case combination can be
- // supported.
- throw new IllegalArgumentException("Failed to add extra fake Preview or "
- + "ImageCapture use case!");
- }
- }
+ Set<UseCase> appUseCasesAfter = new HashSet<>(mUseCases);
+ appUseCasesAfter.removeAll(useCasesToRemove);
+ updateUseCases(appUseCasesAfter);
}
}
/**
+ * Updates the states based the new app UseCases.
+ *
+ * <p> This method calculates the new camera UseCases based on the input and the current state,
+ * attach/detach the camera UseCases, and save the updated state in following member variables:
+ * {@link #mCameraUseCases}, {@link #mUseCases} and {@link #mPlaceholderForExtensions}.
+ *
+ * @throws IllegalArgumentException if the UseCase combination is not supported. In that case,
+ * it will not update the internal states.
+ */
+ void updateUseCases(@NonNull Set<UseCase> appUseCases) {
+ synchronized (mLock) {
+ // Calculate camera UseCases and keep the result in local variables in case they don't
+ // meet the stream combination rules.
+ UseCase placeholderForExtensions = calculatePlaceholderForExtensions(appUseCases);
+ Set<UseCase> cameraUseCases =
+ calculateCameraUseCases(appUseCases, placeholderForExtensions);
+
+ // Calculate the action items.
+ Set<UseCase> cameraUseCasesToAttach = new HashSet<>(cameraUseCases);
+ cameraUseCasesToAttach.removeAll(mCameraUseCases);
+ Set<UseCase> cameraUseCasesToKeep = new HashSet<>(cameraUseCases);
+ cameraUseCasesToKeep.retainAll(mCameraUseCases);
+ Set<UseCase> cameraUseCasesToDetach = new HashSet<>(mCameraUseCases);
+ cameraUseCasesToDetach.removeAll(cameraUseCases);
+
+ // Calculate suggested resolutions. This step throws exception if the camera UseCases
+ // fails the supported stream combination rules.
+ Map<UseCase, ConfigPair> configs = getConfigs(cameraUseCasesToAttach,
+ mCameraConfig.getUseCaseConfigFactory(), mUseCaseConfigFactory);
+ Map<UseCase, Size> suggestedResolutionsMap = calculateSuggestedResolutions(
+ mCameraInternal.getCameraInfoInternal(), cameraUseCasesToAttach,
+ cameraUseCasesToKeep, configs);
+
+ // Update properties.
+ updateViewPort(suggestedResolutionsMap, cameraUseCases);
+ updateEffects(mEffects, appUseCases);
+
+ // Detach unused UseCases.
+ for (UseCase useCase : cameraUseCasesToDetach) {
+ useCase.unbindFromCamera(mCameraInternal);
+ }
+ mCameraInternal.detachUseCases(cameraUseCasesToDetach);
+
+ // Attach new UseCases.
+ for (UseCase useCase : cameraUseCasesToAttach) {
+ ConfigPair configPair = requireNonNull(configs.get(useCase));
+ useCase.bindToCamera(mCameraInternal, configPair.mExtendedConfig,
+ configPair.mCameraConfig);
+ useCase.updateSuggestedResolution(
+ Preconditions.checkNotNull(suggestedResolutionsMap.get(useCase)));
+ }
+ if (mAttached) {
+ mCameraInternal.attachUseCases(cameraUseCasesToAttach);
+ }
+
+ // Once UseCases are detached/attached, notify the camera.
+ for (UseCase useCase : cameraUseCasesToAttach) {
+ useCase.notifyState();
+ }
+
+ // The changes are successful. Update the states of this class.
+ mUseCases.clear();
+ mUseCases.addAll(appUseCases);
+ mCameraUseCases.clear();
+ mCameraUseCases.addAll(cameraUseCases);
+ mPlaceholderForExtensions = placeholderForExtensions;
+ }
+ }
+
+ static Set<UseCase> calculateCameraUseCases(@NonNull Set<UseCase> appUseCases,
+ @Nullable UseCase placeholderForExtensions) {
+ Set<UseCase> useCases = new HashSet<>(appUseCases);
+ if (placeholderForExtensions != null) {
+ useCases.add(placeholderForExtensions);
+ }
+ return useCases;
+ }
+
+ /**
* Returns the UseCases currently associated with the adapter.
*
* <p> The UseCases may or may not be actually attached to the underlying
@@ -316,6 +308,14 @@
}
}
+ @VisibleForTesting
+ @NonNull
+ Set<UseCase> getCameraUseCases() {
+ synchronized (mLock) {
+ return new HashSet<>(mCameraUseCases);
+ }
+ }
+
/**
* Attach the UseCases to the {@link CameraInternal} camera so that the UseCases can receive
* data if they are active.
@@ -395,8 +395,8 @@
private Map<UseCase, Size> calculateSuggestedResolutions(
@NonNull CameraInfoInternal cameraInfoInternal,
- @NonNull List<UseCase> newUseCases,
- @NonNull List<UseCase> currentUseCases,
+ @NonNull Collection<UseCase> newUseCases,
+ @NonNull Collection<UseCase> currentUseCases,
@NonNull Map<UseCase, ConfigPair> configPairMap) {
List<AttachedSurfaceInfo> existingSurfaces = new ArrayList<>();
String cameraId = cameraInfoInternal.getCameraId();
@@ -533,7 +533,7 @@
}
// Get a map of the configs for the use cases from the respective factories
- private Map<UseCase, ConfigPair> getConfigs(List<UseCase> useCases,
+ private Map<UseCase, ConfigPair> getConfigs(Collection<UseCase> useCases,
UseCaseConfigFactory extendedFactory, UseCaseConfigFactory cameraFactory) {
Map<UseCase, ConfigPair> configs = new HashMap<>();
for (UseCase useCase : useCases) {
@@ -658,64 +658,30 @@
}
/**
- * Calculates the new required extra use cases according to the use cases bound by the
- * application and the existing extra use cases.
+ * Calculate the internal created placeholder UseCase for Extensions.
*
- * @param boundUseCases The use cases bound by the application.
- * @param extraUseCases The originally existing extra use cases.
- * @return new required extra use cases
+ * @param appUseCases UseCase provided by the app.
*/
- @NonNull
- private List<UseCase> calculateRequiredExtraUseCases(@NonNull List<UseCase> boundUseCases,
- @NonNull List<UseCase> extraUseCases) {
- List<UseCase> requiredExtraUseCases = new ArrayList<>(extraUseCases);
- boolean isExtraPreviewRequired = isExtraPreviewRequired(boundUseCases);
- boolean isExtraImageCaptureRequired = isExtraImageCaptureRequired(
- boundUseCases);
- UseCase existingExtraPreview = null;
- UseCase existingExtraImageCapture = null;
-
- for (UseCase useCase : extraUseCases) {
- if (isPreview(useCase)) {
- existingExtraPreview = useCase;
- } else if (isImageCapture(useCase)) {
- existingExtraImageCapture = useCase;
- }
- }
-
- if (isExtraPreviewRequired && existingExtraPreview == null) {
- requiredExtraUseCases.add(createExtraPreview());
- } else if (!isExtraPreviewRequired && existingExtraPreview != null) {
- requiredExtraUseCases.remove(existingExtraPreview);
- }
-
- if (isExtraImageCaptureRequired && existingExtraImageCapture == null) {
- requiredExtraUseCases.add(createExtraImageCapture());
- } else if (!isExtraImageCaptureRequired && existingExtraImageCapture != null) {
- requiredExtraUseCases.remove(existingExtraImageCapture);
- }
-
- return requiredExtraUseCases;
- }
-
- /**
- * Detaches unnecessary use cases from camera.
- */
- private void detachUnnecessaryUseCases(@NonNull List<UseCase> unnecessaryUseCases) {
+ @Nullable
+ UseCase calculatePlaceholderForExtensions(@NonNull Set<UseCase> appUseCases) {
synchronized (mLock) {
- if (!unnecessaryUseCases.isEmpty()) {
- mCameraInternal.detachUseCases(unnecessaryUseCases);
-
- for (UseCase useCase : unnecessaryUseCases) {
- if (mUseCases.contains(useCase)) {
- useCase.unbindFromCamera(mCameraInternal);
+ UseCase placeholder = null;
+ if (isCoexistingPreviewImageCaptureRequired()) {
+ if (isExtraPreviewRequired(appUseCases)) {
+ if (isPreview(mPlaceholderForExtensions)) {
+ placeholder = mPlaceholderForExtensions;
} else {
- Logger.e(TAG, "Attempting to detach non-attached UseCase: " + useCase);
+ placeholder = createExtraPreview();
+ }
+ } else if (isExtraImageCaptureRequired(appUseCases)) {
+ if (isImageCapture(mPlaceholderForExtensions)) {
+ placeholder = mPlaceholderForExtensions;
+ } else {
+ placeholder = createExtraImageCapture();
}
}
-
- mUseCases.removeAll(unnecessaryUseCases);
}
+ return placeholder;
}
}
@@ -730,7 +696,7 @@
* Returns true if the input use case list contains a {@link ImageCapture} but does not
* contain an {@link Preview}.
*/
- private boolean isExtraPreviewRequired(@NonNull List<UseCase> useCases) {
+ private boolean isExtraPreviewRequired(@NonNull Collection<UseCase> useCases) {
boolean hasPreview = false;
boolean hasImageCapture = false;
@@ -749,7 +715,7 @@
* Returns true if the input use case list contains a {@link Preview} but does not contain an
* {@link ImageCapture}.
*/
- private boolean isExtraImageCaptureRequired(@NonNull List<UseCase> useCases) {
+ private boolean isExtraImageCaptureRequired(@NonNull Collection<UseCase> useCases) {
boolean hasPreview = false;
boolean hasImageCapture = false;
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharing.java b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharing.java
new file mode 100644
index 0000000..07c714b
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharing.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 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 androidx.camera.core.streamsharing;
+
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.camera.core.ImageCapture;
+import androidx.camera.core.UseCase;
+import androidx.camera.core.impl.CameraInternal;
+import androidx.camera.core.impl.Config;
+import androidx.camera.core.impl.MutableOptionsBundle;
+import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
+
+import java.util.Set;
+
+/**
+ * A {@link UseCase} that shares one PRIV stream to multiple children {@link UseCase}s.
+ */
+@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+public class StreamSharing extends UseCase {
+
+ @SuppressWarnings("UnusedVariable")
+ private final VirtualCamera mVirtualCamera;
+
+ private static final StreamSharingConfig DEFAULT_CONFIG =
+ new StreamSharingBuilder().getUseCaseConfig();
+
+ /**
+ * Constructs a {@link StreamSharing} with a parent {@link CameraInternal}, children
+ * {@link UseCase}s, and a {@link UseCaseConfigFactory} for getting default {@link UseCase}
+ * configurations.
+ */
+ public StreamSharing(@NonNull CameraInternal parentCamera,
+ @NonNull Set<UseCase> children,
+ @NonNull UseCaseConfigFactory useCaseConfigFactory) {
+ this(new VirtualCamera(parentCamera, children, useCaseConfigFactory));
+ }
+
+ StreamSharing(@NonNull VirtualCamera virtualCamera) {
+ super(DEFAULT_CONFIG);
+ mVirtualCamera = virtualCamera;
+ }
+
+ @Nullable
+ @Override
+ public UseCaseConfig<?> getDefaultConfig(boolean applyDefaultConfig,
+ @NonNull UseCaseConfigFactory factory) {
+ // The shared stream optimizes for VideoCapture.
+ Config captureConfig = factory.getConfig(
+ UseCaseConfigFactory.CaptureType.VIDEO_CAPTURE,
+ ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY);
+
+ if (applyDefaultConfig) {
+ captureConfig = Config.mergeConfigs(captureConfig, DEFAULT_CONFIG.getConfig());
+ }
+ return captureConfig == null ? null :
+ getUseCaseConfigBuilder(captureConfig).getUseCaseConfig();
+ }
+
+ @NonNull
+ @Override
+ public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder(@NonNull Config config) {
+ return new StreamSharingBuilder(MutableOptionsBundle.from(config));
+ }
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharingBuilder.java b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharingBuilder.java
new file mode 100644
index 0000000..0ae8daa
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharingBuilder.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright 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 androidx.camera.core.streamsharing;
+
+import static androidx.camera.core.internal.TargetConfig.OPTION_TARGET_CLASS;
+import static androidx.camera.core.internal.TargetConfig.OPTION_TARGET_NAME;
+
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.camera.core.CameraSelector;
+import androidx.camera.core.UseCase;
+import androidx.camera.core.impl.CaptureConfig;
+import androidx.camera.core.impl.MutableConfig;
+import androidx.camera.core.impl.MutableOptionsBundle;
+import androidx.camera.core.impl.OptionsBundle;
+import androidx.camera.core.impl.SessionConfig;
+import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.internal.TargetConfig;
+
+import java.util.UUID;
+
+/**
+ * A empty builder for {@link StreamSharing}.
+ *
+ * <p> {@link StreamSharing} does not need a public builder. Instead, the caller should call the
+ * constructor directly. This class exists because the {@link UseCase#getUseCaseConfigBuilder}
+ * method requires a builder for each {@link UseCase}.
+ */
+@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+class StreamSharingBuilder implements
+ UseCaseConfig.Builder<StreamSharing, StreamSharingConfig, StreamSharingBuilder> {
+
+ private static final String UNSUPPORTED_MESSAGE =
+ "Operation not supported by StreamSharingBuilder.";
+
+ private final MutableOptionsBundle mMutableConfig;
+
+ StreamSharingBuilder() {
+ this(MutableOptionsBundle.create());
+ }
+
+ StreamSharingBuilder(@NonNull MutableOptionsBundle mutableConfig) {
+ mMutableConfig = mutableConfig;
+ Class<?> oldConfigClass =
+ mutableConfig.retrieveOption(TargetConfig.OPTION_TARGET_CLASS, null);
+ if (oldConfigClass != null && !oldConfigClass.equals(StreamSharing.class)) {
+ throw new IllegalArgumentException(
+ "Invalid target class configuration for "
+ + StreamSharingBuilder.this
+ + ": "
+ + oldConfigClass);
+ }
+ setTargetClass(StreamSharing.class);
+ }
+
+ @NonNull
+ @Override
+ public MutableConfig getMutableConfig() {
+ return mMutableConfig;
+ }
+
+ @NonNull
+ @Override
+ public StreamSharing build() {
+ throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
+ }
+
+ @NonNull
+ @Override
+ public StreamSharingBuilder setDefaultSessionConfig(@NonNull SessionConfig sessionConfig) {
+ throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
+ }
+
+ @NonNull
+ @Override
+ public StreamSharingBuilder setDefaultCaptureConfig(@NonNull CaptureConfig captureConfig) {
+ throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
+ }
+
+ @NonNull
+ @Override
+ public StreamSharingBuilder setSessionOptionUnpacker(
+ @NonNull SessionConfig.OptionUnpacker optionUnpacker) {
+ throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
+ }
+
+ @NonNull
+ @Override
+ public StreamSharingBuilder setCaptureOptionUnpacker(
+ @NonNull CaptureConfig.OptionUnpacker optionUnpacker) {
+ throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
+ }
+
+ @NonNull
+ @Override
+ public StreamSharingBuilder setSurfaceOccupancyPriority(int priority) {
+ throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
+ }
+
+ @NonNull
+ @Override
+ public StreamSharingBuilder setCameraSelector(@NonNull CameraSelector cameraSelector) {
+ throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
+ }
+
+ @NonNull
+ @Override
+ public StreamSharingBuilder setZslDisabled(boolean disabled) {
+ throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
+ }
+
+ @NonNull
+ @Override
+ public StreamSharingBuilder setHighResolutionDisabled(boolean disabled) {
+ throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
+ }
+
+ @NonNull
+ @Override
+ public StreamSharingConfig getUseCaseConfig() {
+ return new StreamSharingConfig(OptionsBundle.from(mMutableConfig));
+ }
+
+ @NonNull
+ @Override
+ public StreamSharingBuilder setTargetClass(@NonNull Class<StreamSharing> targetClass) {
+ getMutableConfig().insertOption(OPTION_TARGET_CLASS, targetClass);
+ // If no name is set yet, then generate a unique name
+ if (null == getMutableConfig().retrieveOption(OPTION_TARGET_NAME, null)) {
+ String targetName = targetClass.getCanonicalName() + "-" + UUID.randomUUID();
+ setTargetName(targetName);
+ }
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public StreamSharingBuilder setTargetName(@NonNull String targetName) {
+ getMutableConfig().insertOption(OPTION_TARGET_NAME, targetName);
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public StreamSharingBuilder setUseCaseEventCallback(
+ @NonNull UseCase.EventCallback eventCallback) {
+ throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
+ }
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharingConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharingConfig.java
new file mode 100644
index 0000000..adf1207
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharingConfig.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 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 androidx.camera.core.streamsharing;
+
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.camera.core.impl.Config;
+import androidx.camera.core.impl.ImageOutputConfig;
+import androidx.camera.core.impl.MutableConfig;
+import androidx.camera.core.impl.OptionsBundle;
+import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.internal.ThreadConfig;
+
+/**
+ * Configuration for a {@link StreamSharing} use case.
+ *
+ * <p> This class is a thin wrapper of the underlying {@link OptionsBundle}. Instead of adding
+ * getters and setters to this class, one should modify the config using
+ * {@link MutableConfig#insertOption} and {@link MutableConfig#retrieveOption} directly.
+ */
+@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+class StreamSharingConfig implements UseCaseConfig<StreamSharing>,
+ ImageOutputConfig,
+ ThreadConfig {
+
+ private final OptionsBundle mConfig;
+
+ /** Creates a new configuration instance. */
+ StreamSharingConfig(@NonNull OptionsBundle config) {
+ mConfig = config;
+ }
+
+ @NonNull
+ @Override
+ public Config getConfig() {
+ return mConfig;
+ }
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCamera.java b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCamera.java
new file mode 100644
index 0000000..adf2588
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCamera.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 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 androidx.camera.core.streamsharing;
+
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.camera.core.UseCase;
+import androidx.camera.core.impl.CameraControlInternal;
+import androidx.camera.core.impl.CameraInfoInternal;
+import androidx.camera.core.impl.CameraInternal;
+import androidx.camera.core.impl.Observable;
+import androidx.camera.core.impl.UseCaseConfigFactory;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * A virtual implementation of {@link CameraInternal}.
+ *
+ * <p> This class manages children {@link UseCase} and connects/disconnects them to the
+ * parent {@link StreamSharing}. It also forwards parent camera properties/events to the children.
+ */
+@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+class VirtualCamera implements CameraInternal {
+
+ private static final String UNSUPPORTED_MESSAGE = "Operation not supported by VirtualCamera.";
+
+ @SuppressWarnings("UnusedVariable")
+ @NonNull
+ private final Set<UseCase> mChildren;
+ @SuppressWarnings("UnusedVariable")
+ @NonNull
+ private final UseCaseConfigFactory mUseCaseConfigFactory;
+ @NonNull
+ private final CameraInternal mParentCamera;
+
+ /**
+ * @param parentCamera the parent {@link CameraInternal} instance. For example, the
+ * real camera.
+ * @param children the children {@link UseCase}.
+ * @param useCaseConfigFactory the factory for configuring children {@link UseCase}.
+ */
+ VirtualCamera(@NonNull CameraInternal parentCamera,
+ @NonNull Set<UseCase> children,
+ @NonNull UseCaseConfigFactory useCaseConfigFactory) {
+ mParentCamera = parentCamera;
+ mUseCaseConfigFactory = useCaseConfigFactory;
+ mChildren = children;
+ }
+
+ // --- API for StreamSharing ---
+
+ // TODO(b/264936250): Add methods for interacting with the StreamSharing UseCase.
+
+ // --- Handle children state change ---
+
+ // TODO(b/264936250): Handle children state changes.
+
+ @Override
+ public void onUseCaseActive(@NonNull UseCase useCase) {
+
+ }
+
+ @Override
+ public void onUseCaseInactive(@NonNull UseCase useCase) {
+
+ }
+
+ @Override
+ public void onUseCaseUpdated(@NonNull UseCase useCase) {
+
+ }
+
+ @Override
+ public void onUseCaseReset(@NonNull UseCase useCase) {
+
+ }
+
+ // --- Forward parent camera properties and events ---
+
+ @NonNull
+ @Override
+ public CameraControlInternal getCameraControlInternal() {
+ return mParentCamera.getCameraControlInternal();
+ }
+
+ @NonNull
+ @Override
+ public CameraInfoInternal getCameraInfoInternal() {
+ return mParentCamera.getCameraInfoInternal();
+ }
+
+ @NonNull
+ @Override
+ public Observable<State> getCameraState() {
+ return mParentCamera.getCameraState();
+ }
+
+ // --- Unused overrides ---
+
+ @Override
+ public void open() {
+ throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
+ }
+
+ @Override
+ public void close() {
+ throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
+ }
+
+ @NonNull
+ @Override
+ public ListenableFuture<Void> release() {
+ throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
+ }
+
+ @Override
+ public void attachUseCases(@NonNull Collection<UseCase> useCases) {
+ throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
+ }
+
+ @Override
+ public void detachUseCases(@NonNull Collection<UseCase> useCases) {
+ throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
+ }
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/package-info.java b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/package-info.java
new file mode 100644
index 0000000..fd92612
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 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.
+ */
+
+/**
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+package androidx.camera.core.streamsharing;
+
+import androidx.annotation.RestrictTo;
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.kt
index f34f0c1..216b5d3 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.kt
@@ -445,7 +445,7 @@
cameraUseCaseAdapter.addUseCases(listOf(preview))
// Checks whether an extra ImageCapture is added.
- assertThat(containsImageCapture(cameraUseCaseAdapter.useCases)).isTrue()
+ assertThat(containsImageCapture(cameraUseCaseAdapter.cameraUseCases)).isTrue()
}
@Test
@@ -462,7 +462,7 @@
cameraUseCaseAdapter.addUseCases(listOf(preview))
// Checks whether an extra ImageCapture is added.
- assertThat(containsImageCapture(cameraUseCaseAdapter.useCases))
+ assertThat(containsImageCapture(cameraUseCaseAdapter.cameraUseCases))
val imageCapture = ImageCapture.Builder().build()
// Adds an ImageCapture
@@ -496,7 +496,7 @@
cameraUseCaseAdapter.removeUseCases(listOf(imageCapture))
// Checks whether an extra ImageCapture is added.
- assertThat(containsImageCapture(cameraUseCaseAdapter.useCases)).isTrue()
+ assertThat(containsImageCapture(cameraUseCaseAdapter.cameraUseCases)).isTrue()
}
@Test
@@ -513,7 +513,7 @@
cameraUseCaseAdapter.addUseCases(listOf(imageCapture))
// Checks whether an extra Preview is added.
- assertThat(containsPreview(cameraUseCaseAdapter.useCases)).isTrue()
+ assertThat(containsPreview(cameraUseCaseAdapter.cameraUseCases)).isTrue()
}
@Test
@@ -530,7 +530,7 @@
cameraUseCaseAdapter.addUseCases(listOf(imageCapture))
// Checks whether an extra Preview is added.
- assertThat(containsPreview(cameraUseCaseAdapter.useCases))
+ assertThat(containsPreview(cameraUseCaseAdapter.cameraUseCases))
val preview = Preview.Builder().build()
// Adds an Preview
@@ -563,7 +563,7 @@
cameraUseCaseAdapter.removeUseCases(listOf(preview))
// Checks whether an extra Preview is added.
- assertThat(containsPreview(cameraUseCaseAdapter.useCases)).isTrue()
+ assertThat(containsPreview(cameraUseCaseAdapter.cameraUseCases)).isTrue()
}
@Test
@@ -671,7 +671,7 @@
}
}
- private fun containsPreview(useCases: List<UseCase>): Boolean {
+ private fun containsPreview(useCases: Collection<UseCase>): Boolean {
for (useCase in useCases) {
if (useCase is Preview) {
return true
@@ -680,7 +680,7 @@
return false
}
- private fun containsImageCapture(useCases: List<UseCase>): Boolean {
+ private fun containsImageCapture(useCases: Collection<UseCase>): Boolean {
for (useCase in useCases) {
if (useCase is ImageCapture) {
return true
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/StreamSharingTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/StreamSharingTest.kt
new file mode 100644
index 0000000..3f61631
--- /dev/null
+++ b/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/StreamSharingTest.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright 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 androidx.camera.core.streamsharing
+
+import android.os.Build
+import androidx.camera.core.Preview
+import androidx.camera.core.impl.UseCaseConfigFactory
+import androidx.camera.core.internal.TargetConfig.OPTION_TARGET_CLASS
+import androidx.camera.core.internal.TargetConfig.OPTION_TARGET_NAME
+import androidx.camera.testing.fakes.FakeCamera
+import androidx.camera.testing.fakes.FakeUseCase
+import androidx.camera.testing.fakes.FakeUseCaseConfigFactory
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.internal.DoNotInstrument
+
+/**
+ * Unit tests for [StreamSharing].
+ */
+@RunWith(RobolectricTestRunner::class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+class StreamSharingTest {
+
+ private val parentCamera = FakeCamera()
+ private val preview = Preview.Builder().build()
+ private val video = FakeUseCase()
+ private val useCaseConfigFactory = FakeUseCaseConfigFactory()
+ private lateinit var streamSharing: StreamSharing
+
+ @Before
+ fun setUp() {
+ streamSharing = StreamSharing(parentCamera, setOf(preview, video), useCaseConfigFactory)
+ }
+
+ @Test
+ fun getDefaultConfig_usesVideoCaptureType() {
+ val config = streamSharing.getDefaultConfig(true, useCaseConfigFactory)!!
+
+ assertThat(useCaseConfigFactory.lastRequestedCaptureType)
+ .isEqualTo(UseCaseConfigFactory.CaptureType.VIDEO_CAPTURE)
+ assertThat(
+ config.retrieveOption(
+ OPTION_TARGET_CLASS,
+ null
+ )
+ ).isEqualTo(StreamSharing::class.java)
+ assertThat(
+ config.retrieveOption(
+ OPTION_TARGET_NAME,
+ null
+ )
+ ).startsWith("androidx.camera.core.streamsharing.StreamSharing-")
+ }
+}
\ No newline at end of file
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/VirtualCameraTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/VirtualCameraTest.kt
new file mode 100644
index 0000000..901a70a
--- /dev/null
+++ b/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/VirtualCameraTest.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright 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 androidx.camera.core.streamsharing
+
+import android.os.Build
+import androidx.camera.core.Preview
+import androidx.camera.testing.fakes.FakeCamera
+import androidx.camera.testing.fakes.FakeUseCase
+import androidx.camera.testing.fakes.FakeUseCaseConfigFactory
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.internal.DoNotInstrument
+
+/**
+ * Unit tests for [VirtualCamera].
+ */
+@RunWith(RobolectricTestRunner::class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+class VirtualCameraTest {
+
+ private val parentCamera = FakeCamera()
+ private val preview = Preview.Builder().build()
+ private val video = FakeUseCase()
+ private val useCaseConfigFactory = FakeUseCaseConfigFactory()
+ private lateinit var virtualCamera: VirtualCamera
+
+ @Before
+ fun setUp() {
+ virtualCamera = VirtualCamera(parentCamera, setOf(preview, video), useCaseConfigFactory)
+ }
+
+ @Test
+ fun virtualCameraInheritsParentProperties() {
+ assertThat(virtualCamera.cameraState).isEqualTo(parentCamera.cameraState)
+ assertThat(virtualCamera.cameraInfo).isEqualTo(parentCamera.cameraInfo)
+ assertThat(virtualCamera.cameraControl).isEqualTo(parentCamera.cameraControl)
+ }
+}
\ No newline at end of file
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfigFactory.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfigFactory.java
index c6d68fe9..8cae469 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfigFactory.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfigFactory.java
@@ -36,6 +36,10 @@
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public final class FakeUseCaseConfigFactory implements UseCaseConfigFactory {
+
+ @NonNull
+ private CaptureType mLastRequestedCaptureType;
+
/**
* Returns the configuration for the given capture type, or <code>null</code> if the
* configuration cannot be produced.
@@ -45,6 +49,7 @@
public Config getConfig(
@NonNull CaptureType captureType,
@CaptureMode int captureMode) {
+ mLastRequestedCaptureType = captureType;
MutableOptionsBundle mutableConfig = MutableOptionsBundle.create();
mutableConfig.insertOption(OPTION_CAPTURE_CONFIG_UNPACKER, (config, builder) -> {});
@@ -52,4 +57,9 @@
return OptionsBundle.from(mutableConfig);
}
+
+ @NonNull
+ public CaptureType getLastRequestedCaptureType() {
+ return mLastRequestedCaptureType;
+ }
}
diff --git a/camera/integration-tests/avsynctestapp/src/main/java/androidx/camera/integration/avsync/SignalGeneratorScreen.kt b/camera/integration-tests/avsynctestapp/src/main/java/androidx/camera/integration/avsync/SignalGeneratorScreen.kt
index 2acc74e..a4daab7 100644
--- a/camera/integration-tests/avsynctestapp/src/main/java/androidx/camera/integration/avsync/SignalGeneratorScreen.kt
+++ b/camera/integration-tests/avsynctestapp/src/main/java/androidx/camera/integration/avsync/SignalGeneratorScreen.kt
@@ -21,7 +21,9 @@
import androidx.camera.integration.avsync.ui.widget.AdvancedFloatingActionButton
import androidx.compose.foundation.background
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.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
@@ -89,21 +91,23 @@
) {
Box(modifier = Modifier.fillMaxSize()) {
LightingScreen(isOn = isSignalActive)
- SignalControl(
- enabled = isGeneratorReady,
- isStarted = isSignalStarted,
- onStartClick = onSignalStartClick,
- onStopClick = onSignalStopClick,
- )
- RecordingControl(
- enabled = isRecorderReady,
- isStarted = isRecording,
- isPaused = isPaused,
- onStartClick = onRecordingStartClick,
- onStopClick = onRecordingStopClick,
- onPauseClick = onRecordingPauseClick,
- onResumeClick = onRecordingResumeClick,
- )
+ ControlPanel {
+ SignalControl(
+ enabled = isGeneratorReady,
+ isStarted = isSignalStarted,
+ onStartClick = onSignalStartClick,
+ onStopClick = onSignalStopClick,
+ )
+ RecordingControl(
+ enabled = isRecorderReady,
+ isStarted = isRecording,
+ isPaused = isPaused,
+ onStartClick = onRecordingStartClick,
+ onStopClick = onRecordingStopClick,
+ onPauseClick = onRecordingPauseClick,
+ onResumeClick = onRecordingResumeClick,
+ )
+ }
}
}
@@ -116,6 +120,19 @@
}
@Composable
+private fun ControlPanel(
+ modifier: Modifier = Modifier,
+ content: @Composable () -> Unit
+) {
+ Column(modifier = modifier.fillMaxSize()) {
+ Spacer(modifier = Modifier.weight(2f))
+ Box(modifier = Modifier.weight(1f)) {
+ content()
+ }
+ }
+}
+
+@Composable
private fun SignalControl(
modifier: Modifier = Modifier,
enabled: Boolean,
diff --git a/car/app/app-samples/showcase/common/src/main/res/values-ky/strings.xml b/car/app/app-samples/showcase/common/src/main/res/values-ky/strings.xml
index b776820..d6f99b5 100644
--- a/car/app/app-samples/showcase/common/src/main/res/values-ky/strings.xml
+++ b/car/app/app-samples/showcase/common/src/main/res/values-ky/strings.xml
@@ -35,7 +35,7 @@
<string name="unchecked_action_title" msgid="802503415474307811">"Белгиси алынды"</string>
<string name="on_action_title" msgid="4129601573763429611">"Күйүк"</string>
<string name="off_action_title" msgid="8669201170189204848">"Өчүк"</string>
- <string name="settings_action_title" msgid="8616900063253887861">"Жөндөөлөр"</string>
+ <string name="settings_action_title" msgid="8616900063253887861">"Параметрлер"</string>
<string name="accept_action_title" msgid="4899660585470647578">"Кабыл алуу"</string>
<string name="reject_action_title" msgid="6730366705938402668">"Четке кагуу"</string>
<string name="ok_action_title" msgid="7128494973966098611">"Макул"</string>
@@ -63,7 +63,7 @@
<string name="third_item_checked_toast_msg" msgid="3022450599567347361">"Үчүнчү нерсе текшерилди"</string>
<string name="fifth_item_checked_toast_msg" msgid="1627599668504718594">"Бешинчи элемент текшерилди"</string>
<string name="sixth_item_toast_msg" msgid="6117028866385793707">"Алтынчы нерсе чыкылдатылды"</string>
- <string name="settings_toast_msg" msgid="7697794473002342727">"Жөндөөлөр чыкылдатылды"</string>
+ <string name="settings_toast_msg" msgid="7697794473002342727">"Параметрлер чыкылдатылды"</string>
<string name="parked_toast_msg" msgid="2532422265890824446">"Токтотулган аракети"</string>
<string name="more_toast_msg" msgid="5938288138225509885">"Дагы чыкылдатылган"</string>
<string name="commute_toast_msg" msgid="4112684360647638688">"Өтүү баскычы басылды"</string>
diff --git a/compose/foundation/foundation/api/public_plus_experimental_current.txt b/compose/foundation/foundation/api/public_plus_experimental_current.txt
index c01d3ec..272d94d 100644
--- a/compose/foundation/foundation/api/public_plus_experimental_current.txt
+++ b/compose/foundation/foundation/api/public_plus_experimental_current.txt
@@ -185,10 +185,8 @@
}
@androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public interface OverscrollEffect {
- method public suspend Object? consumePostFling(long velocity, kotlin.coroutines.Continuation<? super kotlin.Unit>);
- method public void consumePostScroll(long initialDragDelta, long overscrollDelta, int source);
- method public suspend Object? consumePreFling(long velocity, kotlin.coroutines.Continuation<? super androidx.compose.ui.unit.Velocity>);
- method public long consumePreScroll(long scrollDelta, int source);
+ method public suspend Object? applyToFling(long velocity, kotlin.jvm.functions.Function2<? super androidx.compose.ui.unit.Velocity,? super kotlin.coroutines.Continuation<? super androidx.compose.ui.unit.Velocity>,?> performFling, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public long applyToScroll(long delta, int source, kotlin.jvm.functions.Function1<? super androidx.compose.ui.geometry.Offset,androidx.compose.ui.geometry.Offset> performScroll);
method public androidx.compose.ui.Modifier getEffectModifier();
method public boolean isInProgress();
property public abstract androidx.compose.ui.Modifier effectModifier;
diff --git a/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/OverscrollSample.kt b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/OverscrollSample.kt
index 072596d..696fa74 100644
--- a/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/OverscrollSample.kt
+++ b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/OverscrollSample.kt
@@ -31,11 +31,9 @@
import androidx.compose.foundation.overscroll
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
@@ -61,37 +59,35 @@
// on the scrollable container.
class OffsetOverscrollEffect(val scope: CoroutineScope) : OverscrollEffect {
private val overscrollOffset = Animatable(0f)
- override fun consumePreScroll(
- scrollDelta: Offset,
- source: NestedScrollSource
+
+ override fun applyToScroll(
+ delta: Offset,
+ source: NestedScrollSource,
+ performScroll: (Offset) -> Offset
): Offset {
// in pre scroll we relax the overscroll if needed
// relaxation: when we are in progress of the overscroll and user scrolls in the
// different direction = substract the overscroll first
- val sameDirection = sign(scrollDelta.y) == sign(overscrollOffset.value)
- return if (abs(overscrollOffset.value) > 0.5 && !sameDirection) {
+ val sameDirection = sign(delta.y) == sign(overscrollOffset.value)
+ val consumedByPreScroll = if (abs(overscrollOffset.value) > 0.5 && !sameDirection) {
val prevOverscrollValue = overscrollOffset.value
- val newOverscrollValue = overscrollOffset.value + scrollDelta.y
+ val newOverscrollValue = overscrollOffset.value + delta.y
if (sign(prevOverscrollValue) != sign(newOverscrollValue)) {
// sign changed, coerce to start scrolling and exit
scope.launch { overscrollOffset.snapTo(0f) }
- Offset(x = 0f, y = scrollDelta.y + prevOverscrollValue)
+ Offset(x = 0f, y = delta.y + prevOverscrollValue)
} else {
scope.launch {
- overscrollOffset.snapTo(overscrollOffset.value + scrollDelta.y)
+ overscrollOffset.snapTo(overscrollOffset.value + delta.y)
}
- scrollDelta.copy(x = 0f)
+ delta.copy(x = 0f)
}
} else {
Offset.Zero
}
- }
-
- override fun consumePostScroll(
- initialDragDelta: Offset,
- overscrollDelta: Offset,
- source: NestedScrollSource
- ) {
+ val leftForScroll = delta - consumedByPreScroll
+ val consumedByScroll = performScroll(leftForScroll)
+ val overscrollDelta = leftForScroll - consumedByScroll
// if it is a drag, not a fling, add the delta left to our over scroll value
if (abs(overscrollDelta.y) > 0.5 && source == NestedScrollSource.Drag) {
scope.launch {
@@ -99,21 +95,25 @@
overscrollOffset.snapTo(overscrollOffset.value + overscrollDelta.y * 0.1f)
}
}
+ return consumedByPreScroll + consumedByScroll
}
- override suspend fun consumePreFling(velocity: Velocity): Velocity = Velocity.Zero
-
- override suspend fun consumePostFling(velocity: Velocity) {
+ override suspend fun applyToFling(
+ velocity: Velocity,
+ performFling: suspend (Velocity) -> Velocity
+ ) {
+ val consumed = performFling(velocity)
// when the fling happens - we just gradually animate our overscroll to 0
+ val remaining = velocity - consumed
overscrollOffset.animateTo(
targetValue = 0f,
- initialVelocity = velocity.y,
+ initialVelocity = remaining.y,
animationSpec = spring()
)
}
override val isInProgress: Boolean
- get() = overscrollOffset.isRunning
+ get() = overscrollOffset.value != 0f
// as we're building an offset modifiers, let's offset of our value we calculated
override val effectModifier: Modifier = Modifier.offset {
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/OverscrollTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/OverscrollTest.kt
index c205a4a..9b004e2 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/OverscrollTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/OverscrollTest.kt
@@ -366,11 +366,10 @@
rule.runOnIdle {
val offset = Offset(0f, 5f)
- controller.consumePostScroll(
- initialDragDelta = offset,
- overscrollDelta = offset,
+ controller.applyToScroll(
+ offset,
source = NestedScrollSource.Drag
- )
+ ) { Offset.Zero }
// we have to disable further invalidation requests as otherwise while the overscroll
// effect is considered active (as it is in a pulled state) this will infinitely
// schedule next invalidation right from the drawing. this will make our test infra
@@ -406,17 +405,23 @@
rule.runOnIdle {
repeat(2) {
val offset = Offset(-10f, -10f)
- assertThat(
- effect.consumePreScroll(offset, NestedScrollSource.Drag)
- ).isEqualTo(Offset.Zero)
- effect.consumePostScroll(offset, offset, NestedScrollSource.Drag)
+ var offsetConsumed: Offset? = null
+
+ effect.applyToScroll(offset, NestedScrollSource.Drag) {
+ offsetConsumed = offset - it
+ Offset.Zero
+ }
+ assertThat(offsetConsumed).isEqualTo(Offset.Zero)
}
val velocity = Velocity(-5f, -5f)
runBlocking {
- assertThat(
- effect.consumePreFling(velocity)
- ).isEqualTo(Velocity.Zero)
- effect.consumePostFling(velocity)
+ var velocityConsumed: Velocity? = null
+
+ effect.applyToFling(velocity) {
+ velocityConsumed = velocity - it
+ Velocity.Zero
+ }
+ assertThat(velocityConsumed!!).isEqualTo(Velocity.Zero)
}
}
}
@@ -433,18 +438,24 @@
rule.runOnIdle {
repeat(2) {
val offset = Offset(0f, 10f)
- assertThat(
- effect.consumePreScroll(offset, NestedScrollSource.Drag)
- ).isEqualTo(Offset.Zero)
- effect.consumePostScroll(offset, offset, NestedScrollSource.Drag)
+ var offsetConsumed: Offset? = null
+
+ effect.applyToScroll(offset, NestedScrollSource.Drag) {
+ offsetConsumed = offset - it
+ Offset.Zero
+ }
+ assertThat(offsetConsumed).isEqualTo(Offset.Zero)
}
val velocity = Velocity(0f, 5f)
runBlocking {
- assertThat(
- effect.consumePreFling(velocity)
- ).isEqualTo(Velocity.Zero)
- effect.consumePostFling(velocity)
+ var velocityConsumed: Velocity? = null
+
+ effect.applyToFling(velocity) {
+ velocityConsumed = velocity - it
+ Velocity.Zero
+ }
+ assertThat(velocityConsumed!!).isEqualTo(Velocity.Zero)
}
}
}
@@ -648,32 +659,32 @@
var preFlingVelocity = Velocity.Zero
- override fun consumePreScroll(
- scrollDelta: Offset,
- source: NestedScrollSource
+ override fun applyToScroll(
+ delta: Offset,
+ source: NestedScrollSource,
+ performScroll: (Offset) -> Offset
): Offset {
- lastPreScrollDelta = scrollDelta
+ lastPreScrollDelta = delta
preScrollSource = source
- return if (consumePreCycles) scrollDelta / 10f else Offset.Zero
- }
+ val consumed = if (consumePreCycles) delta / 10f else Offset.Zero
- override fun consumePostScroll(
- initialDragDelta: Offset,
- overscrollDelta: Offset,
- source: NestedScrollSource
- ) {
- lastInitialDragDelta = initialDragDelta
- lastOverscrollDelta = overscrollDelta
+ val consumedByScroll = performScroll(delta - consumed)
+
+ lastInitialDragDelta = delta
+ lastOverscrollDelta = delta - consumedByScroll - consumed
lastNestedScrollSource = source
+
+ return delta - lastOverscrollDelta
}
- override suspend fun consumePreFling(velocity: Velocity): Velocity {
+ override suspend fun applyToFling(
+ velocity: Velocity,
+ performFling: suspend (Velocity) -> Velocity
+ ) {
preFlingVelocity = velocity
- return if (consumePreCycles) velocity / 10f else Velocity.Zero
- }
-
- override suspend fun consumePostFling(velocity: Velocity) {
+ val consumed = if (consumePreCycles) velocity / 10f else Velocity.Zero
+ performFling(velocity - consumed)
lastVelocity = velocity
}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollableTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
index 5baa306..2345c6e 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
@@ -2552,31 +2552,6 @@
}
}
-@OptIn(ExperimentalFoundationApi::class)
-private val NoOpOverscrollEffect = object : OverscrollEffect {
-
- override fun consumePreScroll(
- scrollDelta: Offset,
- source: NestedScrollSource
- ): Offset = Offset.Zero
-
- override fun consumePostScroll(
- initialDragDelta: Offset,
- overscrollDelta: Offset,
- source: NestedScrollSource
- ) {
- }
-
- override suspend fun consumePreFling(velocity: Velocity): Velocity = Velocity.Zero
-
- override suspend fun consumePostFling(velocity: Velocity) {}
-
- override val isInProgress: Boolean
- get() = false
-
- override val effectModifier: Modifier get() = Modifier
-}
-
// Very low tolerance on the difference
internal val VelocityTrackerCalculationThreshold = 1
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/AndroidOverscroll.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/AndroidOverscroll.kt
index b651632..b5e0699 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/AndroidOverscroll.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/AndroidOverscroll.kt
@@ -63,12 +63,10 @@
internal actual fun rememberOverscrollEffect(): OverscrollEffect {
val context = LocalContext.current
val config = LocalOverscrollConfiguration.current
- return remember(context, config) {
- if (config != null) {
- AndroidEdgeEffectOverscrollEffect(context, config)
- } else {
- NoOpOverscrollEffect
- }
+ return if (config != null) {
+ remember(context, config) { AndroidEdgeEffectOverscrollEffect(context, config) }
+ } else {
+ NoOpOverscrollEffect
}
}
@@ -132,41 +130,44 @@
private var scrollCycleInProgress: Boolean = false
- override fun consumePreScroll(
- scrollDelta: Offset,
- source: NestedScrollSource
+ override fun applyToScroll(
+ delta: Offset,
+ source: NestedScrollSource,
+ performScroll: (Offset) -> Offset
): Offset {
+ // Early return
if (containerSize.isEmpty()) {
- return Offset.Zero
+ return performScroll(delta)
}
+
if (!scrollCycleInProgress) {
stopOverscrollAnimation()
scrollCycleInProgress = true
}
val pointer = pointerPosition ?: containerSize.center
val consumedPixelsY = when {
- scrollDelta.y == 0f -> 0f
+ delta.y == 0f -> 0f
topEffect.distanceCompat != 0f -> {
- pullTop(scrollDelta, pointer).also {
+ pullTop(delta, pointer).also {
if (topEffect.distanceCompat == 0f) topEffect.onRelease()
}
}
bottomEffect.distanceCompat != 0f -> {
- pullBottom(scrollDelta, pointer).also {
+ pullBottom(delta, pointer).also {
if (bottomEffect.distanceCompat == 0f) bottomEffect.onRelease()
}
}
else -> 0f
}
val consumedPixelsX = when {
- scrollDelta.x == 0f -> 0f
+ delta.x == 0f -> 0f
leftEffect.distanceCompat != 0f -> {
- pullLeft(scrollDelta, pointer).also {
+ pullLeft(delta, pointer).also {
if (leftEffect.distanceCompat == 0f) leftEffect.onRelease()
}
}
rightEffect.distanceCompat != 0f -> {
- pullRight(scrollDelta, pointer).also {
+ pullRight(delta, pointer).also {
if (rightEffect.distanceCompat == 0f) rightEffect.onRelease()
}
}
@@ -174,39 +175,39 @@
}
val consumedOffset = Offset(consumedPixelsX, consumedPixelsY)
if (consumedOffset != Offset.Zero) invalidateOverscroll()
- return consumedOffset
- }
- override fun consumePostScroll(
- initialDragDelta: Offset,
- overscrollDelta: Offset,
- source: NestedScrollSource
- ) {
- if (containerSize.isEmpty()) {
- return
- }
+ val leftForDelta = delta - consumedOffset
+ val consumedByDelta = performScroll(leftForDelta)
+ val leftForOverscroll = leftForDelta - consumedByDelta
+
var needsInvalidation = false
if (source == NestedScrollSource.Drag) {
- val pointer = pointerPosition ?: containerSize.center
- if (overscrollDelta.x > 0) {
- pullLeft(overscrollDelta, pointer)
- } else if (overscrollDelta.x < 0) {
- pullRight(overscrollDelta, pointer)
+ if (leftForOverscroll.x > 0) {
+ pullLeft(leftForOverscroll, pointer)
+ } else if (leftForOverscroll.x < 0) {
+ pullRight(leftForOverscroll, pointer)
}
- if (overscrollDelta.y > 0) {
- pullTop(overscrollDelta, pointer)
- } else if (overscrollDelta.y < 0) {
- pullBottom(overscrollDelta, pointer)
+ if (leftForOverscroll.y > 0) {
+ pullTop(leftForOverscroll, pointer)
+ } else if (leftForOverscroll.y < 0) {
+ pullBottom(leftForOverscroll, pointer)
}
- needsInvalidation = overscrollDelta != Offset.Zero || needsInvalidation
+ needsInvalidation = leftForOverscroll != Offset.Zero
}
- needsInvalidation = releaseOppositeOverscroll(initialDragDelta) || needsInvalidation
+ needsInvalidation = releaseOppositeOverscroll(delta) || needsInvalidation
if (needsInvalidation) invalidateOverscroll()
+
+ return consumedOffset + consumedByDelta
}
- override suspend fun consumePreFling(velocity: Velocity): Velocity {
+ override suspend fun applyToFling(
+ velocity: Velocity,
+ performFling: suspend (Velocity) -> Velocity
+ ) {
+ // Early return
if (containerSize.isEmpty()) {
- return Velocity.Zero
+ performFling(velocity)
+ return
}
val consumedX = if (velocity.x > 0f && leftEffect.distanceCompat != 0f) {
leftEffect.onAbsorbCompat(velocity.x.roundToInt())
@@ -228,25 +229,23 @@
}
val consumed = Velocity(consumedX, consumedY)
if (consumed != Velocity.Zero) invalidateOverscroll()
- return consumed
- }
- override suspend fun consumePostFling(velocity: Velocity) {
- if (containerSize.isEmpty()) {
- return
- }
+ val remainingVelocity = velocity - consumed
+ val consumedByVelocity = performFling(remainingVelocity)
+ val leftForOverscroll = remainingVelocity - consumedByVelocity
+
scrollCycleInProgress = false
- if (velocity.x > 0) {
- leftEffect.onAbsorbCompat(velocity.x.roundToInt())
- } else if (velocity.x < 0) {
- rightEffect.onAbsorbCompat(-velocity.x.roundToInt())
+ if (leftForOverscroll.x > 0) {
+ leftEffect.onAbsorbCompat(leftForOverscroll.x.roundToInt())
+ } else if (leftForOverscroll.x < 0) {
+ rightEffect.onAbsorbCompat(-leftForOverscroll.x.roundToInt())
}
- if (velocity.y > 0) {
- topEffect.onAbsorbCompat(velocity.y.roundToInt())
- } else if (velocity.y < 0) {
- bottomEffect.onAbsorbCompat(-velocity.y.roundToInt())
+ if (leftForOverscroll.y > 0) {
+ topEffect.onAbsorbCompat(leftForOverscroll.y.roundToInt())
+ } else if (leftForOverscroll.y < 0) {
+ bottomEffect.onAbsorbCompat(-leftForOverscroll.y.roundToInt())
}
- if (velocity != Velocity.Zero) invalidateOverscroll()
+ if (leftForOverscroll != Velocity.Zero) invalidateOverscroll()
animateToRelease()
}
@@ -489,32 +488,6 @@
}
}
-@OptIn(ExperimentalFoundationApi::class)
-private val NoOpOverscrollEffect = object : OverscrollEffect {
-
- override fun consumePreScroll(
- scrollDelta: Offset,
- source: NestedScrollSource
- ): Offset = Offset.Zero
-
- override fun consumePostScroll(
- initialDragDelta: Offset,
- overscrollDelta: Offset,
- source: NestedScrollSource
- ) {
- }
-
- override suspend fun consumePreFling(velocity: Velocity): Velocity = Velocity.Zero
-
- override suspend fun consumePostFling(velocity: Velocity) {}
-
- override val isInProgress: Boolean
- get() = false
-
- override val effectModifier: Modifier
- get() = Modifier
-}
-
/**
* There is an unwanted behavior in the stretch overscroll effect we have to workaround:
* When the effect is started it is getting the current RenderNode bounds and clips the content
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Overscroll.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Overscroll.kt
index b56d000..c8c89557 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Overscroll.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Overscroll.kt
@@ -24,107 +24,115 @@
import androidx.compose.ui.unit.Velocity
/**
- * Controller to control the overscroll logic for a particular scrollable container.
+ * An OverscrollEffect represents a visual effect that displays when the edges of a scrolling
+ * container have been reached with a scroll or fling. For the default platform effect that should
+ * be used in most cases, see
+ * [androidx.compose.foundation.gestures.ScrollableDefaults.overscrollEffect].
*
- * This entity defines the "how" of the overscroll effect. If the default platform effect is needed,
- * consider using [ScrollableDefaults.overscrollEffect]. In order for overscroll to work,
- * the controller is supposed to be passed to [scrollable] modifier to receive the data of
- * overscroll, and then applied where appropriate using [overscroll] modifier.
+ * OverscrollEffect conceptually 'decorates' scroll / fling events: consuming some of the delta or
+ * velocity before and/or after the event is consumed by the scrolling container. [applyToScroll]
+ * applies overscroll to a scroll event, and [applyToFling] applies overscroll to a fling.
+ *
+ * Higher level components such as [androidx.compose.foundation.lazy.LazyColumn] will automatically
+ * configure an OverscrollEffect for you. To use a custom OverscrollEffect you first need to
+ * provide it with scroll and/or fling events - usually by providing it to a
+ * [androidx.compose.foundation.gestures.scrollable]. Then you can draw the effect on top of the
+ * scrolling content using [Modifier.overscroll].
*
* @sample androidx.compose.foundation.samples.OverscrollSample
*/
@ExperimentalFoundationApi
@Stable
interface OverscrollEffect {
-
/**
- * Consume any overscroll before the scroll happens if needed.
+ * Applies overscroll to [performScroll]. [performScroll] should represent a drag / scroll, and
+ * returns the amount of delta consumed, so in simple cases the amount of overscroll to show
+ * should be equal to `delta - performScroll(delta)`. The OverscrollEffect can optionally
+ * consume some delta before calling [performScroll], such as to release any existing tension.
+ * The implementation *must* call [performScroll] exactly once. This function should return the
+ * sum of all the delta that was consumed during this operation - both by the overscroll and
+ * [performScroll].
*
- * This is usually relevant when the overscroll expresses the effect that is needed to be
- * negated first before actually scrolling. The example might be a spring-based overscroll,
- * where you want to release the tension of a spring before starting to scroll to provide a
- * good user-experience.
- *
- * @param scrollDelta the original delta to scroll
- * @param source source of the scroll event
- *
- * @return the amount of scroll consumed that won't be available for scrollable container
- * anymore
+ * @param delta total scroll delta available
+ * @param source the source of the delta
+ * @param performScroll the scroll action that the overscroll is applied to. The [Offset]
+ * parameter represents how much delta is available, and the return value is how much delta was
+ * consumed. Any delta that was not consumed should be used to show the overscroll effect.
+ * @return the delta consumed from [delta] by the operation of this function - including that
+ * consumed by [performScroll].
*/
- fun consumePreScroll(
- scrollDelta: Offset,
- source: NestedScrollSource
+ fun applyToScroll(
+ delta: Offset,
+ source: NestedScrollSource,
+ performScroll: (Offset) -> Offset
): Offset
/**
- * Process scroll delta that is available after the scroll iteration is over.
+ * Applies overscroll to [performFling]. [performFling] should represent a fling (the release
+ * of a drag or scroll), and returns the amount of [Velocity] consumed, so in simple cases the
+ * amount of overscroll to show should be equal to `velocity - performFling(velocity)`. The
+ * OverscrollEffect can optionally consume some [Velocity] before calling [performFling], such
+ * as to release any existing tension. The implementation *must* call [performFling] exactly
+ * once.
*
- * This is the main method to show an overscroll, as [overscrollDelta] will be a
- * non-[zero][Offset.Zero] only if the scroll is happening at the bound of a scrollable
- * container.
- *
- * @param initialDragDelta initial drag delta before any consumption was made
- * @param overscrollDelta the amount of overscroll left after the scroll process
- * @param source source of the scroll event
+ * @param velocity total [Velocity] available
+ * @param performFling the [Velocity] consuming lambda that the overscroll is applied to. The
+ * [Velocity] parameter represents how much [Velocity] is available, and the return value is how
+ * much [Velocity] was consumed. Any [Velocity] that was not consumed should be used to show the
+ * overscroll effect.
*/
- fun consumePostScroll(
- initialDragDelta: Offset,
- overscrollDelta: Offset,
- source: NestedScrollSource
- )
+ suspend fun applyToFling(velocity: Velocity, performFling: suspend (Velocity) -> Velocity)
/**
- * Consume any velocity for the over scroll effect before the fling happens.
+ * Whether this OverscrollEffect is currently displaying overscroll.
*
- * relevant when the overscroll expresses the effect that is needed to be
- * negated (or increased) first before actually scrolling. The example might be a spring-based
- * overscroll, where you want to release the tension of a spring before starting to scroll to
- * provide a good user-experience.
- *
- * @param velocity velocity available to a scrolling container before flinging
- *
- * @return the amount of velocity that overscroll effect consumed that won't be available for
- * fling operation
- */
- suspend fun consumePreFling(velocity: Velocity): Velocity
-
- /**
- * Feed and process velocity overscroll to show an effect.
- *
- * @param velocity the amount of velocity that is left for overscroll after the fling happened.
- */
- suspend fun consumePostFling(velocity: Velocity)
-
- /**
- * Whether over scroll within this controller is currently on progress or not, e.g. if the
- * overscroll effect is playing animation or shown/interactable in any other way.
- *
- * @return true if there is over scroll happening at the time of the call, false otherwise
+ * @return true if this OverscrollEffect is currently displaying overscroll
*/
val isInProgress: Boolean
/**
- * A modifier that will apply the overscroll effect as desired
+ * A [Modifier] that will draw this OverscrollEffect
*/
val effectModifier: Modifier
}
+/**
+ * Renders overscroll from the provided [overscrollEffect].
+ *
+ * This modifier is a convenience method to call [OverscrollEffect.effectModifier], which
+ * renders the actual effect. Note that this modifier is only responsible for the visual part of
+ * overscroll - on its own it will not handle input events. In addition to using this modifier you
+ * also need to propagate events to the [overscrollEffect], most commonly by using a
+ * [androidx.compose.foundation.gestures.scrollable].
+ *
+ * @sample androidx.compose.foundation.samples.OverscrollSample
+ *
+ * @param overscrollEffect the [OverscrollEffect] to render
+ */
+@ExperimentalFoundationApi
+fun Modifier.overscroll(overscrollEffect: OverscrollEffect): Modifier =
+ this.then(overscrollEffect.effectModifier)
+
@OptIn(ExperimentalFoundationApi::class)
@Composable
internal expect fun rememberOverscrollEffect(): OverscrollEffect
-/**
- * Modifier to apply the overscroll as specified by [OverscrollEffect]
- *
- * This modifier is a convenience method to call [OverscrollEffect.effectModifier], which
- * performs the actual overscroll logic. Note that this modifier is the representation of the
- * overscroll on the UI, to make overscroll events to be propagated to the [OverscrollEffect],
- * you have to pass it to [scrollable].
- *
- * @sample androidx.compose.foundation.samples.OverscrollSample
- *
- * @param overscrollEffect controller that defines the behavior and the overscroll state.
- */
-@ExperimentalFoundationApi
-fun Modifier.overscroll(overscrollEffect: OverscrollEffect): Modifier =
- this.then(overscrollEffect.effectModifier)
\ No newline at end of file
+@OptIn(ExperimentalFoundationApi::class)
+internal object NoOpOverscrollEffect : OverscrollEffect {
+ override fun applyToScroll(
+ delta: Offset,
+ source: NestedScrollSource,
+ performScroll: (Offset) -> Offset
+ ): Offset = performScroll(delta)
+
+ override suspend fun applyToFling(
+ velocity: Velocity,
+ performFling: suspend (Velocity) -> Velocity
+ ) { performFling(velocity) }
+
+ override val isInProgress: Boolean
+ get() = false
+
+ override val effectModifier: Modifier
+ get() = Modifier
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
index 4057fb4..54ce08b 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
@@ -355,61 +355,37 @@
*/
fun ScrollScope.dispatchScroll(availableDelta: Offset, source: NestedScrollSource): Offset {
val scrollDelta = availableDelta.singleAxisOffset()
- val overscrollPreConsumed = overscrollPreConsumeDelta(scrollDelta, source)
- val afterPreOverscroll = scrollDelta - overscrollPreConsumed
- val nestedScrollDispatcher = nestedScrollDispatcher.value
- val preConsumedByParent = nestedScrollDispatcher
- .dispatchPreScroll(afterPreOverscroll, source)
+ val performScroll: (Offset) -> Offset = { delta ->
+ val nestedScrollDispatcher = nestedScrollDispatcher.value
+ val preConsumedByParent = nestedScrollDispatcher
+ .dispatchPreScroll(delta, source)
- val scrollAvailable = afterPreOverscroll - preConsumedByParent
- // Consume on a single axis
- val axisConsumed =
- scrollBy(scrollAvailable.reverseIfNeeded().toFloat()).toOffset().reverseIfNeeded()
+ val scrollAvailable = delta - preConsumedByParent
+ // Consume on a single axis
+ val axisConsumed =
+ scrollBy(scrollAvailable.reverseIfNeeded().toFloat()).toOffset().reverseIfNeeded()
- val leftForParent = scrollAvailable - axisConsumed
- val parentConsumed = nestedScrollDispatcher.dispatchPostScroll(
- axisConsumed,
- leftForParent,
- source
- )
- overscrollPostConsumeDelta(
- scrollAvailable,
- leftForParent - parentConsumed,
- source
- )
+ val leftForParent = scrollAvailable - axisConsumed
+ val parentConsumed = nestedScrollDispatcher.dispatchPostScroll(
+ axisConsumed,
+ leftForParent,
+ source
+ )
- return overscrollPreConsumed + preConsumedByParent + axisConsumed + parentConsumed
+ preConsumedByParent + axisConsumed + parentConsumed
+ }
+
+ return if (overscrollEffect != null && shouldDispatchOverscroll) {
+ overscrollEffect.applyToScroll(scrollDelta, source, performScroll)
+ } else {
+ performScroll(scrollDelta)
+ }
}
private val shouldDispatchOverscroll
get() = scrollableState.canScrollForward || scrollableState.canScrollBackward
- fun overscrollPreConsumeDelta(
- scrollDelta: Offset,
- source: NestedScrollSource
- ): Offset {
- return if (overscrollEffect != null && shouldDispatchOverscroll) {
- overscrollEffect.consumePreScroll(scrollDelta, source)
- } else {
- Offset.Zero
- }
- }
-
- private fun overscrollPostConsumeDelta(
- consumedByChain: Offset,
- availableForOverscroll: Offset,
- source: NestedScrollSource
- ) {
- if (overscrollEffect != null && shouldDispatchOverscroll) {
- overscrollEffect.consumePostScroll(
- consumedByChain,
- availableForOverscroll,
- source
- )
- }
- }
-
fun performRawScroll(scroll: Offset): Offset {
return if (scrollableState.isScrollInProgress) {
Offset.Zero
@@ -424,25 +400,25 @@
registerNestedFling(true)
val availableVelocity = initialVelocity.singleAxisVelocity()
- val preOverscrollConsumed =
- if (overscrollEffect != null && shouldDispatchOverscroll) {
- overscrollEffect.consumePreFling(availableVelocity)
- } else {
- Velocity.Zero
- }
- val velocity = (availableVelocity - preOverscrollConsumed)
- val preConsumedByParent = nestedScrollDispatcher
- .value.dispatchPreFling(velocity)
- val available = velocity - preConsumedByParent
- val velocityLeft = doFlingAnimation(available)
- val consumedPost =
- nestedScrollDispatcher.value.dispatchPostFling(
- (available - velocityLeft),
- velocityLeft
- )
- val totalLeft = velocityLeft - consumedPost
+
+ val performFling: suspend (Velocity) -> Velocity = { velocity ->
+ val preConsumedByParent = nestedScrollDispatcher
+ .value.dispatchPreFling(velocity)
+ val available = velocity - preConsumedByParent
+ val velocityLeft = doFlingAnimation(available)
+ val consumedPost =
+ nestedScrollDispatcher.value.dispatchPostFling(
+ (available - velocityLeft),
+ velocityLeft
+ )
+ val totalLeft = velocityLeft - consumedPost
+ velocity - totalLeft
+ }
+
if (overscrollEffect != null && shouldDispatchOverscroll) {
- overscrollEffect.consumePostFling(totalLeft)
+ overscrollEffect.applyToFling(availableVelocity, performFling)
+ } else {
+ performFling(availableVelocity)
}
// Self stopped flinging, reset
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/DesktopOverscroll.kt b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/DesktopOverscroll.kt
index 75bbcfc..bd9dcef 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/DesktopOverscroll.kt
+++ b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/DesktopOverscroll.kt
@@ -17,37 +17,7 @@
package androidx.compose.foundation
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.input.nestedscroll.NestedScrollSource
-import androidx.compose.ui.unit.Velocity
@OptIn(ExperimentalFoundationApi::class)
@Composable
-internal actual fun rememberOverscrollEffect(): OverscrollEffect {
- return remember {
- DesktopEdgeEffectOverscrollEffect()
- }
-}
-
-@OptIn(ExperimentalFoundationApi::class)
-private class DesktopEdgeEffectOverscrollEffect() : OverscrollEffect {
- override fun consumePreScroll(
- scrollDelta: Offset,
- source: NestedScrollSource
- ): Offset = Offset.Zero
-
- override fun consumePostScroll(
- initialDragDelta: Offset,
- overscrollDelta: Offset,
- source: NestedScrollSource
- ) {}
-
- override suspend fun consumePreFling(velocity: Velocity): Velocity = Velocity.Zero
-
- override suspend fun consumePostFling(velocity: Velocity) {}
-
- override val isInProgress = false
- override val effectModifier = Modifier
-}
+internal actual fun rememberOverscrollEffect(): OverscrollEffect = NoOpOverscrollEffect
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ModalBottomSheetTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ModalBottomSheetTest.kt
index 44bff47..c5cbba9 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ModalBottomSheetTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ModalBottomSheetTest.kt
@@ -267,7 +267,7 @@
sheetContent = {
Box(
Modifier
- .fillMaxSize()
+ .fillMaxSize(0.6f)
.testTag(sheetTag)
)
}
@@ -1137,4 +1137,74 @@
)
.assertWidthIsEqualTo(expectedSheetWidth)
}
+
+ @Test
+ fun modalBottomSheet_shortSheet_anchorChangeHandler_previousTargetNotInAnchors_reconciles() {
+ val sheetState = ModalBottomSheetState(ModalBottomSheetValue.Hidden)
+ var hasSheetContent by mutableStateOf(false) // Start out with empty sheet content
+ lateinit var scope: CoroutineScope
+ rule.setContent {
+ scope = rememberCoroutineScope()
+ ModalBottomSheetLayout(
+ sheetState = sheetState,
+ sheetContent = {
+ if (hasSheetContent) {
+ Box(Modifier.fillMaxHeight(0.4f))
+ }
+ },
+ content = {}
+ )
+ }
+
+ assertThat(sheetState.currentValue).isEqualTo(ModalBottomSheetValue.Hidden)
+ assertThat(sheetState.swipeableState.hasAnchorForValue(ModalBottomSheetValue.HalfExpanded))
+ .isFalse()
+ assertThat(sheetState.swipeableState.hasAnchorForValue(ModalBottomSheetValue.Expanded))
+ .isFalse()
+
+ scope.launch { sheetState.show() }
+ rule.waitForIdle()
+
+ assertThat(sheetState.isVisible).isTrue()
+ assertThat(sheetState.currentValue).isEqualTo(sheetState.targetValue)
+
+ hasSheetContent = true // Recompose with sheet content
+ rule.waitForIdle()
+ assertThat(sheetState.currentValue).isEqualTo(ModalBottomSheetValue.Expanded)
+ }
+
+ @Test
+ fun modalBottomSheet_tallSheet_anchorChangeHandler_previousTargetNotInAnchors_reconciles() {
+ val sheetState = ModalBottomSheetState(ModalBottomSheetValue.Hidden)
+ var hasSheetContent by mutableStateOf(false) // Start out with empty sheet content
+ lateinit var scope: CoroutineScope
+ rule.setContent {
+ scope = rememberCoroutineScope()
+ ModalBottomSheetLayout(
+ sheetState = sheetState,
+ sheetContent = {
+ if (hasSheetContent) {
+ Box(Modifier.fillMaxHeight(0.6f))
+ }
+ },
+ content = {}
+ )
+ }
+
+ assertThat(sheetState.currentValue).isEqualTo(ModalBottomSheetValue.Hidden)
+ assertThat(sheetState.swipeableState.hasAnchorForValue(ModalBottomSheetValue.HalfExpanded))
+ .isFalse()
+ assertThat(sheetState.swipeableState.hasAnchorForValue(ModalBottomSheetValue.Expanded))
+ .isFalse()
+
+ scope.launch { sheetState.show() }
+ rule.waitForIdle()
+
+ assertThat(sheetState.isVisible).isTrue()
+ assertThat(sheetState.currentValue).isEqualTo(sheetState.targetValue)
+
+ hasSheetContent = true // Recompose with sheet content
+ rule.waitForIdle()
+ assertThat(sheetState.currentValue).isEqualTo(ModalBottomSheetValue.HalfExpanded)
+ }
}
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SnackbarHostTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SnackbarHostTest.kt
index 18ac04d..1ded9e5 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SnackbarHostTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SnackbarHostTest.kt
@@ -33,6 +33,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.filters.MediumTest
+import androidx.test.filters.RequiresDevice
import com.google.common.truth.Truth
import com.nhaarman.mockitokotlin2.any
import com.nhaarman.mockitokotlin2.doReturn
@@ -82,6 +83,7 @@
rule.waitUntil { job.isCompleted }
}
+ @RequiresDevice // b/264895456
@Test
fun snackbarHost_fifoQueueContract() {
var resultedInvocation = ""
@@ -111,6 +113,7 @@
Truth.assertThat(resultedInvocation).isEqualTo("0123456789")
}
+ @RequiresDevice // b/264895456
@Test
@LargeTest
fun snackbarHost_returnedResult() {
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ModalBottomSheet.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ModalBottomSheet.kt
index d15e372..5ea9086 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ModalBottomSheet.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ModalBottomSheet.kt
@@ -499,9 +499,9 @@
when (state) {
Hidden -> fullHeight
HalfExpanded -> when {
- sheetSize.height < fullHeight / 2 -> null
+ sheetSize.height < fullHeight / 2f -> null
sheetState.isSkipHalfExpanded -> null
- else -> sheetSize.height / 2f
+ else -> fullHeight / 2f
}
Expanded -> if (sheetSize.height != 0) {
@@ -656,7 +656,7 @@
animateTo: (target: ModalBottomSheetValue, velocity: Float) -> Unit,
snapTo: (target: ModalBottomSheetValue) -> Unit,
) = AnchorChangeHandler<ModalBottomSheetValue> { previousTarget, previousAnchors, newAnchors ->
- val previousTargetOffset = previousAnchors.getValue(previousTarget)
+ val previousTargetOffset = previousAnchors[previousTarget]
val newTarget = when (previousTarget) {
Hidden -> Hidden
HalfExpanded, Expanded -> {
diff --git a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/clock/AnimateXAsStateClockTest.kt b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/clock/AnimateXAsStateClockTest.kt
index 323824b..f58d39d 100644
--- a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/clock/AnimateXAsStateClockTest.kt
+++ b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/clock/AnimateXAsStateClockTest.kt
@@ -77,7 +77,7 @@
checkUpdatedState(clock, label = "DpAnimation",
newInitialValue = 1.dp, newTargetValue = 2.dp,
composeState = { state!!.value })
- rule.runOnUiThread { clock.setStateParameters(listOf(3.dp), listOf(4.dp)) }
+ rule.runOnUiThread { clock.setStateParameters(3f, 4.0) }
checkUpdatedState(clock, label = "DpAnimation",
newInitialValue = 3.dp, newTargetValue = 4.dp,
composeState = { state!!.value })
@@ -89,7 +89,7 @@
composeState = { state!!.value })
// Invalid parameters are ignored.
rule.runOnUiThread {
- clock.setStateParameters(111.dp, 111)
+ clock.setStateParameters(111.dp, "")
clock.setStateParameters(111.dp, null)
clock.setStateParameters(listOf(111.dp), listOf(111L))
clock.setStateParameters(listOf(null), listOf(null))
diff --git a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/clock/UtilsTest.kt b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/clock/UtilsTest.kt
new file mode 100644
index 0000000..a5cf31a
--- /dev/null
+++ b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/clock/UtilsTest.kt
@@ -0,0 +1,294 @@
+/*
+ * Copyright 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 androidx.compose.ui.tooling.animation.clock
+
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.tooling.animation.states.TargetState
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.dp
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Test
+
+class UtilsTest {
+
+ @Test
+ fun currentValueIsNull() {
+ val value = parseParametersToValue<Int?>(null, 20, 30)
+ assertNull(value)
+ }
+
+ @Test
+ fun par2IsNull() {
+ val value = parseParametersToValue(10, 20, null)
+ assertNull(value)
+ }
+
+ @Test
+ fun currentValueHasDifferentType() {
+ val value = parseParametersToValue(10f, 20, 30)
+ assertNull(value)
+ }
+
+ @Test
+ fun par1HasDifferentType() {
+ val value = parseParametersToValue(10, 20f, 30)
+ assertNull(value)
+ }
+
+ @Test
+ fun par2HasDifferentType() {
+ val value = parseParametersToValue(10, 20, 30f)
+ assertNull(value)
+ }
+
+ @Test
+ fun listsHasNull() {
+ val value = parseParametersToValue(IntSize(10, 20), listOf(10, null), listOf(20, 30))
+ assertNull(value)
+ }
+
+ @Test
+ fun listsAreEmpty() {
+ val value = parseParametersToValue(IntSize(10, 20), emptyList<Int>(), emptyList<Int>())
+ assertNull(value)
+ }
+
+ @Test
+ fun offsetOutOfBounds() {
+ val value = parseParametersToValue(
+ Offset(10f, 20f),
+ listOf(30f),
+ listOf(50f, 60f)
+ )
+ assertNull(value)
+ }
+
+ @Test
+ fun offsetIncorrectType() {
+ val value = parseParametersToValue(
+ Offset(10f, 20f),
+ listOf("a", "b"),
+ listOf(50f, 60f)
+ )
+ assertNull(value)
+ }
+
+ @Test
+ fun intIsParsed() {
+ val value = parseParametersToValue(10, 20, 30)
+ assertEquals(TargetState(20, 30), value)
+ }
+
+ @Test
+ fun intIsParsedAsList() {
+ val value = parseParametersToValue(10, listOf(20), listOf(30))
+ assertEquals(TargetState(20, 30), value)
+ }
+
+ @Test
+ fun stringIsParsed() {
+ val value = parseParametersToValue("a", "b", "c")
+ assertEquals(TargetState("b", "c"), value)
+ }
+
+ @Test
+ fun stringIsParsedAsList() {
+ val value = parseParametersToValue("a", listOf("b"), listOf("c"))
+ assertEquals(TargetState("b", "c"), value)
+ }
+
+ @Test
+ fun booleanIsParsed() {
+ val value = parseParametersToValue(currentValue = false, par1 = true, par2 = false)
+ assertEquals(TargetState(initial = true, target = false), value)
+ }
+
+ @Test
+ fun booleanIsParsedAsList() {
+ val value = parseParametersToValue(false, listOf(true), listOf(false))
+ assertEquals(TargetState(initial = true, target = false), value)
+ }
+
+ @Test
+ fun dpIsParsed() {
+ val value = parseParametersToValue(10.dp, 20.dp, 30.dp)
+ assertEquals(TargetState(20.dp, 30.dp), value)
+ }
+
+ @Test
+ fun dpIsParsedAsDoubleAndFloat() {
+ val value = parseParametersToValue(10.dp, 20.0, 30f)
+ assertEquals(TargetState(20.dp, 30.dp), value)
+ }
+
+ @Test
+ fun dpIsParsedAsList() {
+ val value = parseParametersToValue(10.dp, listOf(20f), listOf(30f))
+ assertEquals(TargetState(20.dp, 30.dp), value)
+ }
+
+ @Test
+ fun dpIsParsedAsDoubleAndFloatList() {
+ val value = parseParametersToValue(10.dp, listOf(20.0), listOf(30f))
+ assertEquals(TargetState(20.dp, 30.dp), value)
+ }
+
+ @Test
+ fun intSizeIsParsed() {
+ val value = parseParametersToValue(
+ IntSize(10, 20),
+ IntSize(30, 40),
+ IntSize(50, 60)
+ )
+ assertEquals(TargetState(IntSize(30, 40), IntSize(50, 60)), value)
+ }
+
+ @Test
+ fun intSizeIsParsedAsList() {
+ val value = parseParametersToValue(
+ IntSize(10, 20),
+ listOf(30, 40),
+ listOf(50, 60)
+ )
+ assertEquals(TargetState(IntSize(30, 40), IntSize(50, 60)), value)
+ }
+
+ @Test
+ fun intOffsetIsParsed() {
+ val value = parseParametersToValue(
+ IntOffset(10, 20),
+ IntOffset(30, 40),
+ IntOffset(50, 60)
+ )
+ assertEquals(TargetState(IntOffset(30, 40), IntOffset(50, 60)), value)
+ }
+
+ @Test
+ fun intOffsetIsParsedAsList() {
+ val value = parseParametersToValue(
+ IntOffset(10, 20),
+ listOf(30, 40),
+ listOf(50, 60)
+ )
+ assertEquals(TargetState(IntOffset(30, 40), IntOffset(50, 60)), value)
+ }
+
+ @Test
+ fun sizeIsParsed() {
+ val value = parseParametersToValue(
+ Size(10f, 20f),
+ Size(30f, 40f),
+ Size(50f, 60f)
+ )
+ assertEquals(TargetState(Size(30f, 40f), Size(50f, 60f)), value)
+ }
+
+ @Test
+ fun sizeIsParsedAsList() {
+ val value = parseParametersToValue(
+ Size(10f, 20f),
+ listOf(30f, 40f),
+ listOf(50f, 60f)
+ )
+ assertEquals(TargetState(Size(30f, 40f), Size(50f, 60f)), value)
+ }
+
+ @Test
+ fun offsetIsParsed() {
+ val value = parseParametersToValue(
+ Offset(10f, 20f),
+ Offset(30f, 40f),
+ Offset(50f, 60f)
+ )
+ assertEquals(TargetState(Offset(30f, 40f), Offset(50f, 60f)), value)
+ }
+
+ @Test
+ fun offsetIsParsedAsList() {
+ val value = parseParametersToValue(
+ Offset(10f, 20f),
+ listOf(30f, 40f),
+ listOf(50f, 60f)
+ )
+ assertEquals(TargetState(Offset(30f, 40f), Offset(50f, 60f)), value)
+ }
+
+ @Test
+ fun rectIsParsed() {
+ val value = parseParametersToValue(
+ Rect(10f, 20f, 30f, 40f),
+ Rect(50f, 60f, 70f, 80f),
+ Rect(90f, 100f, 110f, 120f)
+ )
+ assertEquals(
+ TargetState(
+ Rect(50f, 60f, 70f, 80f),
+ Rect(90f, 100f, 110f, 120f)
+ ), value
+ )
+ }
+
+ @Test
+ fun rectIsParsedAsList() {
+ val value = parseParametersToValue(
+ Rect(10f, 20f, 30f, 40f),
+ listOf(50f, 60f, 70f, 80f),
+ listOf(90f, 100f, 110f, 120f)
+ )
+ assertEquals(
+ TargetState(
+ Rect(50f, 60f, 70f, 80f),
+ Rect(90f, 100f, 110f, 120f)
+ ), value
+ )
+ }
+
+ @Test
+ fun colorIsParsed() {
+ val value = parseParametersToValue(
+ Color(0.1f, 0.2f, 0.3f, 0.4f),
+ Color(0.5f, 0.6f, 0.7f, 0.8f),
+ Color(0.55f, 0.65f, 0.75f, 0.85f)
+ )
+ assertEquals(
+ TargetState(
+ Color(0.5f, 0.6f, 0.7f, 0.8f),
+ Color(0.55f, 0.65f, 0.75f, 0.85f)
+ ), value
+ )
+ }
+
+ @Test
+ fun colorIsParsedAsList() {
+ val value = parseParametersToValue(
+ Color(0.1f, 0.2f, 0.3f, 0.4f),
+ listOf(0.5f, 0.6f, 0.7f, 0.8f),
+ listOf(0.55f, 0.65f, 0.75f, 0.85f)
+ )
+ assertEquals(
+ TargetState(
+ Color(0.5f, 0.6f, 0.7f, 0.8f),
+ Color(0.55f, 0.65f, 0.75f, 0.85f)
+ ), value
+ )
+ }
+}
\ No newline at end of file
diff --git a/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/animation/clock/Utils.kt b/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/animation/clock/Utils.kt
index fad8a64..ae1f769 100644
--- a/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/animation/clock/Utils.kt
+++ b/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/animation/clock/Utils.kt
@@ -98,11 +98,13 @@
animationSpec.initialStartOffset.offsetMillis
else 0L
}
+
is InfiniteRepeatableSpec<*> -> {
if (animationSpec.initialStartOffset.offsetType == StartOffsetType.Delay)
animationSpec.initialStartOffset.offsetMillis
else 0L
}
+
is VectorizedDurationBasedAnimationSpec<*> -> animationSpec.delayMillis
else -> 0L
}.toLong()
@@ -154,19 +156,42 @@
)
}
+/**
+ * [parseParametersToValue] makes sure what [currentValue], [par1], [par2] have the same types and
+ * returned [TargetState] always has correct and the same type as [currentValue].
+ */
@Suppress("UNCHECKED_CAST")
internal fun <T> parseParametersToValue(currentValue: T, par1: Any, par2: Any?): TargetState<T>? {
currentValue ?: return null
+ /** Check if [par1] and [par2] are not null and have the same type. */
fun parametersAreValid(par1: Any?, par2: Any?): Boolean {
return par1 != null && par2 != null && par1::class == par2::class
}
+ /** Check if all parameters have the same type. */
fun parametersHasTheSameType(value: Any, par1: Any, par2: Any): Boolean {
return value::class == par1::class && value::class == par2::class
}
+ fun getDp(par: Any): Dp? {
+ return (par as? Dp) ?: (par as? Float)?.dp ?: (par as? Double)?.dp ?: (par as? Int)?.dp
+ }
+
+ fun parseDp(par1: Any, par2: Any?): TargetState<Dp>? {
+ if (currentValue !is Dp || par2 == null) return null
+ return if (par1 is Dp && par2 is Dp)
+ TargetState(par1, par2) else {
+ val dp1 = getDp(par1)
+ val dp2 = getDp(par2)
+ if (dp1 != null && dp2 != null)
+ TargetState(dp1, dp2) else null
+ }
+ }
+ // Dp could be presented as Float/Double/Int - try to parse it.
+ parseDp(par1, par2)?.let { return it as TargetState<T> }
+
if (!parametersAreValid(par1, par2)) return null
if (parametersHasTheSameType(currentValue, par1, par2!!)) {
@@ -227,12 +252,8 @@
),
)
- is Dp -> {
- if (parametersHasTheSameType(currentValue, par1[0]!!, par2[0]!!))
- TargetState(par1[0], par2[0]) else TargetState(
- (par1[0] as Float).dp, (par2[0] as Float).dp
- )
- }
+ is Dp ->
+ parseDp(par1[0]!!, par2[0]!!)
else -> {
if (parametersAreValid(par1[0], par2[0]) &&
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/SdkConfig.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/SdkConfig.java
index 92456f9..3e2ec2d 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/SdkConfig.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/SdkConfig.java
@@ -25,7 +25,7 @@
@RestrictTo(RestrictTo.Scope.LIBRARY)
public final class SdkConfig {
// should be increased everytime a new SDK is released
- public static final int SDK_VERSION = 9;
+ public static final int SDK_VERSION = 10;
private SdkConfig() {}
}
diff --git a/media2/media2-widget/src/main/res/values-ky/strings.xml b/media2/media2-widget/src/main/res/values-ky/strings.xml
index 2452d322..c53b918 100644
--- a/media2/media2-widget/src/main/res/values-ky/strings.xml
+++ b/media2/media2-widget/src/main/res/values-ky/strings.xml
@@ -35,7 +35,7 @@
<string name="mcv2_overflow_left_button_desc" msgid="2749567167276435888">"Мурунку баскыч тизмесине кайтуу"</string>
<string name="mcv2_overflow_right_button_desc" msgid="7388732945289831383">"Дагы баскычтарды көрүү"</string>
<string name="mcv2_seek_bar_desc" msgid="24915699029009384">"Ойнотуу көрсөткүчү"</string>
- <string name="mcv2_settings_button_desc" msgid="811917224044739656">"Жөндөөлөр"</string>
+ <string name="mcv2_settings_button_desc" msgid="811917224044739656">"Параметрлер"</string>
<string name="mcv2_cc_is_on" msgid="5427119422911561783">"Коштомо жазуу күйүк. Жашыруу үчүн чыкылдатыңыз."</string>
<string name="mcv2_cc_is_off" msgid="2380791179816122456">"Коштомо жазуу өчүк. Аны көрсөтүү үчүн чыкылдатыңыз."</string>
<string name="mcv2_replay_button_desc" msgid="3128622733570179596">"Кайрадан ойнотуу"</string>
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/TestUtils.kt b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/TestUtils.kt
index 66b5d74..c6be61c 100644
--- a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/TestUtils.kt
+++ b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/TestUtils.kt
@@ -28,7 +28,7 @@
*/
fun compileWithPrivacySandboxKspCompiler(
sources: List<Source>,
- platformStubs: PlatformStubs = PlatformStubs.SDK_RUNTIME_LIBRARY,
+ addSdkRuntimeLibraryStubs: Boolean = true,
extraProcessorOptions: Map<String, String> = mapOf(),
): TestCompilationResult {
val provider = PrivacySandboxKspCompiler.Provider()
@@ -41,17 +41,12 @@
}
return CompilationTestHelper.compileAll(
- sources + platformStubs.sources,
+ if (addSdkRuntimeLibraryStubs) sources + syntheticSdkRuntimeLibraryStubs else sources,
symbolProcessorProviders = listOf(provider),
processorOptions = processorOptions,
)
}
-enum class PlatformStubs(val sources: List<Source>) {
- API_33(syntheticApi33PrivacySandboxStubs),
- SDK_RUNTIME_LIBRARY(syntheticSdkRuntimeLibraryStubs),
-}
-
// SDK Runtime library is not available in AndroidX prebuilts, so while that's the case we use fake
// stubs to run our compilation tests.
private val syntheticSdkRuntimeLibraryStubs = listOf(
@@ -95,60 +90,3 @@
|""".trimMargin()
)
)
-
-// PrivacySandbox platform APIs are not available in AndroidX prebuilts nor are they stable, so
-// while that's the case we use fake stubs to run our compilation tests.
-val syntheticApi33PrivacySandboxStubs = listOf(
- Source.java(
- "android.app.sdksandbox.SandboxedSdk", """
- |package android.app.sdksandbox;
- |
- |import android.os.IBinder;
- |
- |public final class SandboxedSdk {
- | public SandboxedSdk(IBinder sdkInterface) {}
- | public IBinder getInterface() { throw new RuntimeException("Stub!"); }
- |}
- |""".trimMargin()
- ),
- Source.java(
- "android.app.sdksandbox.SandboxedSdkProvider", """
- |package android.app.sdksandbox;
- |
- |import android.content.Context;
- |import android.os.Bundle;
- |import android.view.View;
- |
- |public abstract class SandboxedSdkProvider {
- | public final void attachContext(Context context) {
- | throw new RuntimeException("Stub!");
- | }
- | public final Context getContext() {
- | throw new RuntimeException("Stub!");
- | }
- | public abstract SandboxedSdk onLoadSdk(Bundle params)
- | throws LoadSdkException;
- |
- | public void beforeUnloadSdk() {}
- |
- | public abstract View getView(
- | Context windowContext, Bundle params, int width, int height);
- |}
- |""".trimMargin()
- ),
- Source.java(
- "android.app.sdksandbox.LoadSdkException", """
- |package android.app.sdksandbox;
- |
- |@SuppressWarnings("serial")
- |public final class LoadSdkException extends Exception {}
- |""".trimMargin()
- ),
- Source.java(
- "android.app.sdksandbox.SandboxedSdkContext", """
- |package android.app.sdksandbox;
- |
- |public final class SandboxedSdkContext {}
- |""".trimMargin()
- ),
-)
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/WithoutRuntimeLibrarySdkTest.kt b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/WithoutRuntimeLibrarySdkTest.kt
index 0c98829..aeeca05 100644
--- a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/WithoutRuntimeLibrarySdkTest.kt
+++ b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/WithoutRuntimeLibrarySdkTest.kt
@@ -34,7 +34,7 @@
val result = compileWithPrivacySandboxKspCompiler(
inputSources,
- platformStubs = PlatformStubs.API_33,
+ addSdkRuntimeLibraryStubs = false,
extraProcessorOptions = mapOf("skip_sdk_runtime_compat_library" to "true")
)
assertThat(result).succeeds()
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/Carousel.kt b/tv/tv-material/src/main/java/androidx/tv/material3/Carousel.kt
index d4b5887..60fa29f 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/Carousel.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/Carousel.kt
@@ -118,10 +118,10 @@
var isAutoScrollActive by remember { mutableStateOf(false) }
AutoScrollSideEffect(
- timeToDisplaySlideMillis,
- slideCount,
- carouselState,
- focusState,
+ timeToDisplaySlideMillis = timeToDisplaySlideMillis,
+ slideCount = slideCount,
+ carouselState = carouselState,
+ doAutoScroll = shouldPerformAutoScroll(focusState),
onAutoScrollChange = { isAutoScrollActive = it })
Box(modifier = modifier
@@ -159,6 +159,13 @@
}
}
+@Composable
+private fun shouldPerformAutoScroll(focusState: FocusState?): Boolean {
+ val carouselIsFocused = focusState?.isFocused ?: false
+ val carouselHasFocus = focusState?.hasFocus ?: false
+ return (carouselIsFocused || carouselHasFocus).not()
+}
+
@Suppress("IllegalExperimentalApiUsage")
@OptIn(ExperimentalAnimationApi::class)
private suspend fun AnimatedVisibilityScope.onAnimationCompletion(action: suspend () -> Unit) {
@@ -172,14 +179,11 @@
timeToDisplaySlideMillis: Long,
slideCount: Int,
carouselState: CarouselState,
- focusState: FocusState?,
+ doAutoScroll: Boolean,
onAutoScrollChange: (isAutoScrollActive: Boolean) -> Unit = {},
) {
val currentTimeToDisplaySlideMillis by rememberUpdatedState(timeToDisplaySlideMillis)
val currentSlideCount by rememberUpdatedState(slideCount)
- val carouselIsFocused = focusState?.isFocused ?: false
- val carouselHasFocus = focusState?.hasFocus ?: false
- val doAutoScroll = (carouselIsFocused || carouselHasFocus).not()
if (doAutoScroll) {
LaunchedEffect(carouselState) {
diff --git a/wear/compose/compose-foundation/src/androidAndroidTest/kotlin/androidx/wear/compose/foundation/lazy/ScalingLazyColumnTest.kt b/wear/compose/compose-foundation/src/androidAndroidTest/kotlin/androidx/wear/compose/foundation/lazy/ScalingLazyColumnTest.kt
index 9eb2282..b07f84b3 100644
--- a/wear/compose/compose-foundation/src/androidAndroidTest/kotlin/androidx/wear/compose/foundation/lazy/ScalingLazyColumnTest.kt
+++ b/wear/compose/compose-foundation/src/androidAndroidTest/kotlin/androidx/wear/compose/foundation/lazy/ScalingLazyColumnTest.kt
@@ -964,6 +964,42 @@
assertThat(state.centerItemIndex).isEqualTo(24)
assertThat(state.centerItemScrollOffset).isEqualTo(0)
}
+
+ @Test
+ fun centerItemIndexPublishesUpdatesOnChangeOnly() {
+ lateinit var state: ScalingLazyListState
+ var recompositionCount = 0
+
+ rule.setContent {
+ state = rememberScalingLazyListState(initialCenterItemIndex = 0)
+
+ WithTouchSlop(0f) {
+ state.centerItemIndex
+ recompositionCount++
+
+ ScalingLazyColumn(
+ state = state,
+ modifier = Modifier.testTag(TEST_TAG).requiredSize(
+ itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
+ ),
+ autoCentering = AutoCenteringParams(itemIndex = 0)
+ ) {
+ items(5) {
+ Box(Modifier.requiredSize(itemSizeDp))
+ }
+ }
+ }
+ }
+ // TODO(b/210654937): Remove the waitUntil once we no longer need 2 stage initialization
+ rule.waitUntil { state.initialized.value }
+
+ rule.onNodeWithTag(TEST_TAG).performTouchInput {
+ swipeUp(endY = bottom - (itemSizePx.toFloat() + defaultItemSpacingPx.toFloat()))
+ }
+
+ rule.waitForIdle()
+ assertThat(recompositionCount).isEqualTo(2)
+ }
}
internal const val TestTouchSlop = 18f
diff --git a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/lazy/ScalingLazyListState.kt b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/lazy/ScalingLazyListState.kt
index fd00b16..9241dd6 100644
--- a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/lazy/ScalingLazyListState.kt
+++ b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/lazy/ScalingLazyListState.kt
@@ -104,14 +104,17 @@
private val incompleteScrollOffset = mutableStateOf<Int?>(null)
private val incompleteScrollAnimated = mutableStateOf(false)
+ private val _centerItemIndex = derivedStateOf {
+ (layoutInfo as? DefaultScalingLazyListLayoutInfo)?.let {
+ if (it.initialized) it.centerItemIndex else null
+ } ?: initialCenterItemIndex
+ }
+
/**
* The index of the item positioned closest to the viewport center
*/
public val centerItemIndex: Int
- get() =
- (layoutInfo as? DefaultScalingLazyListLayoutInfo)?.let {
- if (it.initialized) it.centerItemIndex else null
- } ?: initialCenterItemIndex
+ get() = _centerItemIndex.value
internal val topAutoCenteringItemSizePx: Int by derivedStateOf {
if (extraPaddingPx.value == null || scalingParams.value == null ||
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnTest.kt
index 2549f15..a0ef0e1 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnTest.kt
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnTest.kt
@@ -964,6 +964,42 @@
assertThat(state.centerItemIndex).isEqualTo(24)
assertThat(state.centerItemScrollOffset).isEqualTo(0)
}
+
+ @Test
+ fun centerItemIndexPublishesUpdatesOnChangeOnly() {
+ lateinit var state: ScalingLazyListState
+ var recompositionCount = 0
+
+ rule.setContent {
+ state = rememberScalingLazyListState(initialCenterItemIndex = 0)
+
+ WithTouchSlop(0f) {
+ state.centerItemIndex
+ recompositionCount++
+
+ ScalingLazyColumn(
+ state = state,
+ modifier = Modifier.testTag(TEST_TAG).requiredSize(
+ itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
+ ),
+ autoCentering = AutoCenteringParams(itemIndex = 0)
+ ) {
+ items(5) {
+ Box(Modifier.requiredSize(itemSizeDp))
+ }
+ }
+ }
+ }
+ // TODO(b/210654937): Remove the waitUntil once we no longer need 2 stage initialization
+ rule.waitUntil { state.initialized.value }
+
+ rule.onNodeWithTag(TEST_TAG).performTouchInput {
+ swipeUp(endY = bottom - (itemSizePx.toFloat() + defaultItemSpacingPx.toFloat()))
+ }
+
+ rule.waitForIdle()
+ assertThat(recompositionCount).isEqualTo(2)
+ }
}
internal const val TestTouchSlop = 18f
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListState.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListState.kt
index ea0ba02..2926cca 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListState.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListState.kt
@@ -110,14 +110,17 @@
private val incompleteScrollOffset = mutableStateOf<Int?>(null)
private val incompleteScrollAnimated = mutableStateOf(false)
+ private val _centerItemIndex = derivedStateOf {
+ (layoutInfo as? DefaultScalingLazyListLayoutInfo)?.let {
+ if (it.initialized) it.centerItemIndex else null
+ } ?: initialCenterItemIndex
+ }
+
/**
* The index of the item positioned closest to the viewport center
*/
public val centerItemIndex: Int
- get() =
- (layoutInfo as? DefaultScalingLazyListLayoutInfo)?.let {
- if (it.initialized) it.centerItemIndex else null
- } ?: initialCenterItemIndex
+ get() = _centerItemIndex.value
internal val topAutoCenteringItemSizePx: Int by derivedStateOf {
if (extraPaddingPx.value == null || scalingParams.value == null ||
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/SwipeToDismissBox.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/SwipeToDismissBox.kt
index 84af177e..ed29bf9 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/SwipeToDismissBox.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/SwipeToDismissBox.kt
@@ -40,6 +40,7 @@
import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
@@ -159,18 +160,13 @@
Modifiers(
contentForeground = Modifier
.fillMaxSize()
- .graphicsLayer(
- translationX = translationX,
- scaleX = scale,
- scaleY = scale,
- )
- .then(
- if (isRound && translationX > 0) {
- Modifier.clip(CircleShape)
- } else {
- Modifier
- }
- )
+ .graphicsLayer {
+ this.translationX = translationX
+ scaleX = scale
+ scaleY = scale
+ clip = isRound && translationX > 0
+ shape = if (isRound) CircleShape else RectangleShape
+ }
.background(backgroundScrimColor),
scrimForeground =
Modifier
diff --git a/wear/protolayout/protolayout/api/current.txt b/wear/protolayout/protolayout/api/current.txt
index e6f50d0..080e325 100644
--- a/wear/protolayout/protolayout/api/current.txt
+++ b/wear/protolayout/protolayout/api/current.txt
@@ -1 +1,984 @@
// Signature format: 4.0
+package androidx.wear.protolayout {
+
+ public final class ActionBuilders {
+ method public static androidx.wear.protolayout.ActionBuilders.AndroidBooleanExtra booleanExtra(boolean);
+ method public static androidx.wear.protolayout.ActionBuilders.AndroidDoubleExtra doubleExtra(double);
+ method public static androidx.wear.protolayout.ActionBuilders.AndroidIntExtra intExtra(int);
+ method public static androidx.wear.protolayout.ActionBuilders.AndroidLongExtra longExtra(long);
+ method public static androidx.wear.protolayout.ActionBuilders.AndroidStringExtra stringExtra(String);
+ }
+
+ public static interface ActionBuilders.Action {
+ }
+
+ public static interface ActionBuilders.Action.Builder {
+ method public androidx.wear.protolayout.ActionBuilders.Action build();
+ }
+
+ public static final class ActionBuilders.AndroidActivity {
+ method public String getClassName();
+ method public java.util.Map<java.lang.String!,androidx.wear.protolayout.ActionBuilders.AndroidExtra!> getKeyToExtraMapping();
+ method public String getPackageName();
+ }
+
+ public static final class ActionBuilders.AndroidActivity.Builder {
+ ctor public ActionBuilders.AndroidActivity.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidActivity.Builder addKeyToExtraMapping(String, androidx.wear.protolayout.ActionBuilders.AndroidExtra);
+ method public androidx.wear.protolayout.ActionBuilders.AndroidActivity build();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidActivity.Builder setClassName(String);
+ method public androidx.wear.protolayout.ActionBuilders.AndroidActivity.Builder setPackageName(String);
+ }
+
+ public static final class ActionBuilders.AndroidBooleanExtra implements androidx.wear.protolayout.ActionBuilders.AndroidExtra {
+ method public boolean getValue();
+ }
+
+ public static final class ActionBuilders.AndroidBooleanExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ ctor public ActionBuilders.AndroidBooleanExtra.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidBooleanExtra build();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidBooleanExtra.Builder setValue(boolean);
+ }
+
+ public static final class ActionBuilders.AndroidDoubleExtra implements androidx.wear.protolayout.ActionBuilders.AndroidExtra {
+ method public double getValue();
+ }
+
+ public static final class ActionBuilders.AndroidDoubleExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ ctor public ActionBuilders.AndroidDoubleExtra.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidDoubleExtra build();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidDoubleExtra.Builder setValue(double);
+ }
+
+ public static interface ActionBuilders.AndroidExtra {
+ }
+
+ public static interface ActionBuilders.AndroidExtra.Builder {
+ method public androidx.wear.protolayout.ActionBuilders.AndroidExtra build();
+ }
+
+ public static final class ActionBuilders.AndroidIntExtra implements androidx.wear.protolayout.ActionBuilders.AndroidExtra {
+ method public int getValue();
+ }
+
+ public static final class ActionBuilders.AndroidIntExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ ctor public ActionBuilders.AndroidIntExtra.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidIntExtra build();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidIntExtra.Builder setValue(int);
+ }
+
+ public static final class ActionBuilders.AndroidLongExtra implements androidx.wear.protolayout.ActionBuilders.AndroidExtra {
+ method public long getValue();
+ }
+
+ public static final class ActionBuilders.AndroidLongExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ ctor public ActionBuilders.AndroidLongExtra.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidLongExtra build();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidLongExtra.Builder setValue(long);
+ }
+
+ public static final class ActionBuilders.AndroidStringExtra implements androidx.wear.protolayout.ActionBuilders.AndroidExtra {
+ method public String getValue();
+ }
+
+ public static final class ActionBuilders.AndroidStringExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ ctor public ActionBuilders.AndroidStringExtra.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidStringExtra build();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidStringExtra.Builder setValue(String);
+ }
+
+ public static final class ActionBuilders.LaunchAction implements androidx.wear.protolayout.ActionBuilders.Action {
+ method public androidx.wear.protolayout.ActionBuilders.AndroidActivity? getAndroidActivity();
+ }
+
+ public static final class ActionBuilders.LaunchAction.Builder implements androidx.wear.protolayout.ActionBuilders.Action.Builder {
+ ctor public ActionBuilders.LaunchAction.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.LaunchAction build();
+ method public androidx.wear.protolayout.ActionBuilders.LaunchAction.Builder setAndroidActivity(androidx.wear.protolayout.ActionBuilders.AndroidActivity);
+ }
+
+ public static final class ActionBuilders.LoadAction implements androidx.wear.protolayout.ActionBuilders.Action {
+ method public androidx.wear.protolayout.StateBuilders.State? getRequestState();
+ }
+
+ public static final class ActionBuilders.LoadAction.Builder implements androidx.wear.protolayout.ActionBuilders.Action.Builder {
+ ctor public ActionBuilders.LoadAction.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.LoadAction build();
+ method public androidx.wear.protolayout.ActionBuilders.LoadAction.Builder setRequestState(androidx.wear.protolayout.StateBuilders.State);
+ }
+
+ public final class ColorBuilders {
+ method public static androidx.wear.protolayout.ColorBuilders.ColorProp argb(@ColorInt int);
+ }
+
+ public static final class ColorBuilders.ColorProp {
+ method @ColorInt public int getArgb();
+ }
+
+ public static final class ColorBuilders.ColorProp.Builder {
+ ctor public ColorBuilders.ColorProp.Builder();
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp build();
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp.Builder setArgb(@ColorInt int);
+ }
+
+ public final class DeviceParametersBuilders {
+ field public static final int DEVICE_PLATFORM_UNDEFINED = 0; // 0x0
+ field public static final int DEVICE_PLATFORM_WEAR_OS = 1; // 0x1
+ field public static final int SCREEN_SHAPE_RECT = 2; // 0x2
+ field public static final int SCREEN_SHAPE_ROUND = 1; // 0x1
+ field public static final int SCREEN_SHAPE_UNDEFINED = 0; // 0x0
+ }
+
+ public static final class DeviceParametersBuilders.DeviceParameters {
+ method public int getDevicePlatform();
+ method @FloatRange(from=0.0, fromInclusive=false, toInclusive=false) public float getScreenDensity();
+ method @Dimension(unit=androidx.annotation.Dimension.DP) public int getScreenHeightDp();
+ method public int getScreenShape();
+ method @Dimension(unit=androidx.annotation.Dimension.DP) public int getScreenWidthDp();
+ }
+
+ public static final class DeviceParametersBuilders.DeviceParameters.Builder {
+ ctor public DeviceParametersBuilders.DeviceParameters.Builder();
+ method public androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters build();
+ method public androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters.Builder setDevicePlatform(int);
+ method public androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters.Builder setScreenDensity(@FloatRange(from=0.0, fromInclusive=false, toInclusive=false) float);
+ method public androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters.Builder setScreenHeightDp(@Dimension(unit=androidx.annotation.Dimension.DP) int);
+ method public androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters.Builder setScreenShape(int);
+ method public androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters.Builder setScreenWidthDp(@Dimension(unit=androidx.annotation.Dimension.DP) int);
+ }
+
+ public final class DimensionBuilders {
+ method public static androidx.wear.protolayout.DimensionBuilders.DegreesProp degrees(float);
+ method public static androidx.wear.protolayout.DimensionBuilders.DpProp dp(@Dimension(unit=androidx.annotation.Dimension.DP) float);
+ method public static androidx.wear.protolayout.DimensionBuilders.EmProp em(int);
+ method public static androidx.wear.protolayout.DimensionBuilders.EmProp em(float);
+ method public static androidx.wear.protolayout.DimensionBuilders.ExpandedDimensionProp expand();
+ method public static androidx.wear.protolayout.DimensionBuilders.SpProp sp(@Dimension(unit=androidx.annotation.Dimension.SP) float);
+ method public static androidx.wear.protolayout.DimensionBuilders.WrappedDimensionProp wrap();
+ }
+
+ public static interface DimensionBuilders.ContainerDimension {
+ }
+
+ public static interface DimensionBuilders.ContainerDimension.Builder {
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension build();
+ }
+
+ public static final class DimensionBuilders.DegreesProp {
+ method public float getValue();
+ }
+
+ public static final class DimensionBuilders.DegreesProp.Builder {
+ ctor public DimensionBuilders.DegreesProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.DegreesProp build();
+ method public androidx.wear.protolayout.DimensionBuilders.DegreesProp.Builder setValue(float);
+ }
+
+ public static final class DimensionBuilders.DpProp implements androidx.wear.protolayout.DimensionBuilders.ContainerDimension androidx.wear.protolayout.DimensionBuilders.ImageDimension androidx.wear.protolayout.DimensionBuilders.SpacerDimension {
+ method @Dimension(unit=androidx.annotation.Dimension.DP) public float getValue();
+ }
+
+ public static final class DimensionBuilders.DpProp.Builder implements androidx.wear.protolayout.DimensionBuilders.ContainerDimension.Builder androidx.wear.protolayout.DimensionBuilders.ImageDimension.Builder androidx.wear.protolayout.DimensionBuilders.SpacerDimension.Builder {
+ ctor public DimensionBuilders.DpProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp build();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp.Builder setValue(@Dimension(unit=androidx.annotation.Dimension.DP) float);
+ }
+
+ public static final class DimensionBuilders.EmProp {
+ method public float getValue();
+ }
+
+ public static final class DimensionBuilders.EmProp.Builder {
+ ctor public DimensionBuilders.EmProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.EmProp build();
+ method public androidx.wear.protolayout.DimensionBuilders.EmProp.Builder setValue(float);
+ }
+
+ public static final class DimensionBuilders.ExpandedDimensionProp implements androidx.wear.protolayout.DimensionBuilders.ContainerDimension androidx.wear.protolayout.DimensionBuilders.ImageDimension {
+ }
+
+ public static final class DimensionBuilders.ExpandedDimensionProp.Builder implements androidx.wear.protolayout.DimensionBuilders.ContainerDimension.Builder androidx.wear.protolayout.DimensionBuilders.ImageDimension.Builder {
+ ctor public DimensionBuilders.ExpandedDimensionProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.ExpandedDimensionProp build();
+ }
+
+ public static interface DimensionBuilders.ImageDimension {
+ }
+
+ public static interface DimensionBuilders.ImageDimension.Builder {
+ method public androidx.wear.protolayout.DimensionBuilders.ImageDimension build();
+ }
+
+ public static final class DimensionBuilders.ProportionalDimensionProp implements androidx.wear.protolayout.DimensionBuilders.ImageDimension {
+ method @IntRange(from=0) public int getAspectRatioHeight();
+ method @IntRange(from=0) public int getAspectRatioWidth();
+ }
+
+ public static final class DimensionBuilders.ProportionalDimensionProp.Builder implements androidx.wear.protolayout.DimensionBuilders.ImageDimension.Builder {
+ ctor public DimensionBuilders.ProportionalDimensionProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.ProportionalDimensionProp build();
+ method public androidx.wear.protolayout.DimensionBuilders.ProportionalDimensionProp.Builder setAspectRatioHeight(@IntRange(from=0) int);
+ method public androidx.wear.protolayout.DimensionBuilders.ProportionalDimensionProp.Builder setAspectRatioWidth(@IntRange(from=0) int);
+ }
+
+ public static final class DimensionBuilders.SpProp {
+ method @Dimension(unit=androidx.annotation.Dimension.SP) public float getValue();
+ }
+
+ public static final class DimensionBuilders.SpProp.Builder {
+ ctor public DimensionBuilders.SpProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.SpProp build();
+ method public androidx.wear.protolayout.DimensionBuilders.SpProp.Builder setValue(@Dimension(unit=androidx.annotation.Dimension.SP) float);
+ }
+
+ public static interface DimensionBuilders.SpacerDimension {
+ }
+
+ public static interface DimensionBuilders.SpacerDimension.Builder {
+ method public androidx.wear.protolayout.DimensionBuilders.SpacerDimension build();
+ }
+
+ public static final class DimensionBuilders.WrappedDimensionProp implements androidx.wear.protolayout.DimensionBuilders.ContainerDimension {
+ }
+
+ public static final class DimensionBuilders.WrappedDimensionProp.Builder implements androidx.wear.protolayout.DimensionBuilders.ContainerDimension.Builder {
+ ctor public DimensionBuilders.WrappedDimensionProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.WrappedDimensionProp build();
+ }
+
+ public final class LayoutElementBuilders {
+ field public static final int ARC_ANCHOR_CENTER = 2; // 0x2
+ field public static final int ARC_ANCHOR_END = 3; // 0x3
+ field public static final int ARC_ANCHOR_START = 1; // 0x1
+ field public static final int ARC_ANCHOR_UNDEFINED = 0; // 0x0
+ field public static final int CONTENT_SCALE_MODE_CROP = 2; // 0x2
+ field public static final int CONTENT_SCALE_MODE_FILL_BOUNDS = 3; // 0x3
+ field public static final int CONTENT_SCALE_MODE_FIT = 1; // 0x1
+ field public static final int CONTENT_SCALE_MODE_UNDEFINED = 0; // 0x0
+ field public static final int FONT_VARIANT_BODY = 2; // 0x2
+ field public static final int FONT_VARIANT_TITLE = 1; // 0x1
+ field public static final int FONT_VARIANT_UNDEFINED = 0; // 0x0
+ field public static final int FONT_WEIGHT_BOLD = 700; // 0x2bc
+ field public static final int FONT_WEIGHT_NORMAL = 400; // 0x190
+ field public static final int FONT_WEIGHT_UNDEFINED = 0; // 0x0
+ field public static final int HORIZONTAL_ALIGN_CENTER = 2; // 0x2
+ field public static final int HORIZONTAL_ALIGN_END = 5; // 0x5
+ field public static final int HORIZONTAL_ALIGN_LEFT = 1; // 0x1
+ field public static final int HORIZONTAL_ALIGN_RIGHT = 3; // 0x3
+ field public static final int HORIZONTAL_ALIGN_START = 4; // 0x4
+ field public static final int HORIZONTAL_ALIGN_UNDEFINED = 0; // 0x0
+ field public static final int SPAN_VERTICAL_ALIGN_BOTTOM = 1; // 0x1
+ field public static final int SPAN_VERTICAL_ALIGN_TEXT_BASELINE = 2; // 0x2
+ field public static final int SPAN_VERTICAL_ALIGN_UNDEFINED = 0; // 0x0
+ field public static final int TEXT_ALIGN_CENTER = 2; // 0x2
+ field public static final int TEXT_ALIGN_END = 3; // 0x3
+ field public static final int TEXT_ALIGN_START = 1; // 0x1
+ field public static final int TEXT_ALIGN_UNDEFINED = 0; // 0x0
+ field public static final int TEXT_OVERFLOW_ELLIPSIZE_END = 2; // 0x2
+ field public static final int TEXT_OVERFLOW_TRUNCATE = 1; // 0x1
+ field public static final int TEXT_OVERFLOW_UNDEFINED = 0; // 0x0
+ field public static final int VERTICAL_ALIGN_BOTTOM = 3; // 0x3
+ field public static final int VERTICAL_ALIGN_CENTER = 2; // 0x2
+ field public static final int VERTICAL_ALIGN_TOP = 1; // 0x1
+ field public static final int VERTICAL_ALIGN_UNDEFINED = 0; // 0x0
+ }
+
+ public static final class LayoutElementBuilders.Arc implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public androidx.wear.protolayout.DimensionBuilders.DegreesProp? getAnchorAngle();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAnchorTypeProp? getAnchorType();
+ method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement!> getContents();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp? getVerticalAlign();
+ }
+
+ public static final class LayoutElementBuilders.Arc.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Arc.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder setAnchorAngle(androidx.wear.protolayout.DimensionBuilders.DegreesProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder setAnchorType(androidx.wear.protolayout.LayoutElementBuilders.ArcAnchorTypeProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder setAnchorType(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder setVerticalAlign(androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder setVerticalAlign(int);
+ }
+
+ public static final class LayoutElementBuilders.ArcAdapter implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement {
+ method public androidx.wear.protolayout.LayoutElementBuilders.LayoutElement? getContent();
+ method public androidx.wear.protolayout.TypeBuilders.BoolProp? getRotateContents();
+ }
+
+ public static final class LayoutElementBuilders.ArcAdapter.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ ctor public LayoutElementBuilders.ArcAdapter.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAdapter build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAdapter.Builder setContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAdapter.Builder setRotateContents(androidx.wear.protolayout.TypeBuilders.BoolProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAdapter.Builder setRotateContents(boolean);
+ }
+
+ public static final class LayoutElementBuilders.ArcAnchorTypeProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.ArcAnchorTypeProp.Builder {
+ ctor public LayoutElementBuilders.ArcAnchorTypeProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAnchorTypeProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAnchorTypeProp.Builder setValue(int);
+ }
+
+ public static interface LayoutElementBuilders.ArcLayoutElement {
+ }
+
+ public static interface LayoutElementBuilders.ArcLayoutElement.Builder {
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement build();
+ }
+
+ public static final class LayoutElementBuilders.ArcLine implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement {
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp? getColor();
+ method public androidx.wear.protolayout.DimensionBuilders.DegreesProp? getLength();
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers? getModifiers();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getThickness();
+ }
+
+ public static final class LayoutElementBuilders.ArcLine.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ ctor public LayoutElementBuilders.ArcLine.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine.Builder setLength(androidx.wear.protolayout.DimensionBuilders.DegreesProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.ArcModifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine.Builder setThickness(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ }
+
+ public static final class LayoutElementBuilders.ArcSpacer implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement {
+ method public androidx.wear.protolayout.DimensionBuilders.DegreesProp? getLength();
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers? getModifiers();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getThickness();
+ }
+
+ public static final class LayoutElementBuilders.ArcSpacer.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ ctor public LayoutElementBuilders.ArcSpacer.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcSpacer build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcSpacer.Builder setLength(androidx.wear.protolayout.DimensionBuilders.DegreesProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcSpacer.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.ArcModifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcSpacer.Builder setThickness(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ }
+
+ public static final class LayoutElementBuilders.ArcText implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement {
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle? getFontStyle();
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers? getModifiers();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp? getText();
+ }
+
+ public static final class LayoutElementBuilders.ArcText.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ ctor public LayoutElementBuilders.ArcText.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcText build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcText.Builder setFontStyle(androidx.wear.protolayout.LayoutElementBuilders.FontStyle);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcText.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.ArcModifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcText.Builder setText(androidx.wear.protolayout.TypeBuilders.StringProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcText.Builder setText(String);
+ }
+
+ public static final class LayoutElementBuilders.Box implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.LayoutElement!> getContents();
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getHeight();
+ method public androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp? getHorizontalAlignment();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp? getVerticalAlignment();
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getWidth();
+ }
+
+ public static final class LayoutElementBuilders.Box.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Box.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setHorizontalAlignment(androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setHorizontalAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setVerticalAlignment(androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setVerticalAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
+ }
+
+ public static final class LayoutElementBuilders.ColorFilter {
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp? getTint();
+ }
+
+ public static final class LayoutElementBuilders.ColorFilter.Builder {
+ ctor public LayoutElementBuilders.ColorFilter.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ColorFilter build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ColorFilter.Builder setTint(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ }
+
+ public static final class LayoutElementBuilders.Column implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.LayoutElement!> getContents();
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getHeight();
+ method public androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp? getHorizontalAlignment();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getWidth();
+ }
+
+ public static final class LayoutElementBuilders.Column.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Column.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder setHorizontalAlignment(androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder setHorizontalAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
+ }
+
+ public static final class LayoutElementBuilders.ContentScaleModeProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.ContentScaleModeProp.Builder {
+ ctor public LayoutElementBuilders.ContentScaleModeProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ContentScaleModeProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ContentScaleModeProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.FontStyle {
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp? getColor();
+ method public androidx.wear.protolayout.TypeBuilders.BoolProp? getItalic();
+ method public androidx.wear.protolayout.DimensionBuilders.EmProp? getLetterSpacing();
+ method public androidx.wear.protolayout.DimensionBuilders.SpProp? getSize();
+ method public androidx.wear.protolayout.TypeBuilders.BoolProp? getUnderline();
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontWeightProp? getWeight();
+ }
+
+ public static final class LayoutElementBuilders.FontStyle.Builder {
+ ctor public LayoutElementBuilders.FontStyle.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setItalic(androidx.wear.protolayout.TypeBuilders.BoolProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setItalic(boolean);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setLetterSpacing(androidx.wear.protolayout.DimensionBuilders.EmProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setSize(androidx.wear.protolayout.DimensionBuilders.SpProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setUnderline(androidx.wear.protolayout.TypeBuilders.BoolProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setUnderline(boolean);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setWeight(androidx.wear.protolayout.LayoutElementBuilders.FontWeightProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setWeight(int);
+ }
+
+ public static class LayoutElementBuilders.FontStyles {
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder body1(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder body2(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder button(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder caption1(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder caption2(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder display1(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder display2(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder display3(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder title1(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder title2(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder title3(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ }
+
+ public static final class LayoutElementBuilders.FontWeightProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.FontWeightProp.Builder {
+ ctor public LayoutElementBuilders.FontWeightProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontWeightProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontWeightProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.HorizontalAlignmentProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.HorizontalAlignmentProp.Builder {
+ ctor public LayoutElementBuilders.HorizontalAlignmentProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.Image implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public androidx.wear.protolayout.LayoutElementBuilders.ColorFilter? getColorFilter();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ContentScaleModeProp? getContentScaleMode();
+ method public androidx.wear.protolayout.DimensionBuilders.ImageDimension? getHeight();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp? getResourceId();
+ method public androidx.wear.protolayout.DimensionBuilders.ImageDimension? getWidth();
+ }
+
+ public static final class LayoutElementBuilders.Image.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Image.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setColorFilter(androidx.wear.protolayout.LayoutElementBuilders.ColorFilter);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setContentScaleMode(androidx.wear.protolayout.LayoutElementBuilders.ContentScaleModeProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setContentScaleMode(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.ImageDimension);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setResourceId(androidx.wear.protolayout.TypeBuilders.StringProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setResourceId(String);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.ImageDimension);
+ }
+
+ public static final class LayoutElementBuilders.Layout {
+ method public static androidx.wear.protolayout.LayoutElementBuilders.Layout fromLayoutElement(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.LayoutElement? getRoot();
+ }
+
+ public static final class LayoutElementBuilders.Layout.Builder {
+ ctor public LayoutElementBuilders.Layout.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Layout build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Layout.Builder setRoot(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ }
+
+ public static interface LayoutElementBuilders.LayoutElement {
+ }
+
+ public static interface LayoutElementBuilders.LayoutElement.Builder {
+ method public androidx.wear.protolayout.LayoutElementBuilders.LayoutElement build();
+ }
+
+ public static final class LayoutElementBuilders.Row implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.LayoutElement!> getContents();
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getHeight();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp? getVerticalAlignment();
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getWidth();
+ }
+
+ public static final class LayoutElementBuilders.Row.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Row.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder setVerticalAlignment(androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder setVerticalAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
+ }
+
+ public static final class LayoutElementBuilders.Spacer implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public androidx.wear.protolayout.DimensionBuilders.SpacerDimension? getHeight();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.DimensionBuilders.SpacerDimension? getWidth();
+ }
+
+ public static final class LayoutElementBuilders.Spacer.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Spacer.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spacer build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spacer.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.SpacerDimension);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spacer.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spacer.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.SpacerDimension);
+ }
+
+ public static interface LayoutElementBuilders.Span {
+ }
+
+ public static interface LayoutElementBuilders.Span.Builder {
+ method public androidx.wear.protolayout.LayoutElementBuilders.Span build();
+ }
+
+ public static final class LayoutElementBuilders.SpanImage implements androidx.wear.protolayout.LayoutElementBuilders.Span {
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanVerticalAlignmentProp? getAlignment();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getHeight();
+ method public androidx.wear.protolayout.ModifiersBuilders.SpanModifiers? getModifiers();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp? getResourceId();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getWidth();
+ }
+
+ public static final class LayoutElementBuilders.SpanImage.Builder implements androidx.wear.protolayout.LayoutElementBuilders.Span.Builder {
+ ctor public LayoutElementBuilders.SpanImage.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setAlignment(androidx.wear.protolayout.LayoutElementBuilders.SpanVerticalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.SpanModifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setResourceId(androidx.wear.protolayout.TypeBuilders.StringProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setResourceId(String);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ }
+
+ public static final class LayoutElementBuilders.SpanText implements androidx.wear.protolayout.LayoutElementBuilders.Span {
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle? getFontStyle();
+ method public androidx.wear.protolayout.ModifiersBuilders.SpanModifiers? getModifiers();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp? getText();
+ }
+
+ public static final class LayoutElementBuilders.SpanText.Builder implements androidx.wear.protolayout.LayoutElementBuilders.Span.Builder {
+ ctor public LayoutElementBuilders.SpanText.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanText build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanText.Builder setFontStyle(androidx.wear.protolayout.LayoutElementBuilders.FontStyle);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanText.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.SpanModifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanText.Builder setText(androidx.wear.protolayout.TypeBuilders.StringProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanText.Builder setText(String);
+ }
+
+ public static final class LayoutElementBuilders.SpanVerticalAlignmentProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.SpanVerticalAlignmentProp.Builder {
+ ctor public LayoutElementBuilders.SpanVerticalAlignmentProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanVerticalAlignmentProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanVerticalAlignmentProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.Spannable implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public androidx.wear.protolayout.DimensionBuilders.SpProp? getLineHeight();
+ method public androidx.wear.protolayout.TypeBuilders.Int32Prop? getMaxLines();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp? getMultilineAlignment();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextOverflowProp? getOverflow();
+ method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.Span!> getSpans();
+ }
+
+ public static final class LayoutElementBuilders.Spannable.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Spannable.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder addSpan(androidx.wear.protolayout.LayoutElementBuilders.Span);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setLineHeight(androidx.wear.protolayout.DimensionBuilders.SpProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setMaxLines(androidx.wear.protolayout.TypeBuilders.Int32Prop);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setMaxLines(@IntRange(from=1) int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setMultilineAlignment(androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setMultilineAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setOverflow(androidx.wear.protolayout.LayoutElementBuilders.TextOverflowProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setOverflow(int);
+ }
+
+ public static final class LayoutElementBuilders.Text implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle? getFontStyle();
+ method public androidx.wear.protolayout.DimensionBuilders.SpProp? getLineHeight();
+ method public androidx.wear.protolayout.TypeBuilders.Int32Prop? getMaxLines();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextAlignmentProp? getMultilineAlignment();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextOverflowProp? getOverflow();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp? getText();
+ }
+
+ public static final class LayoutElementBuilders.Text.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Text.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setFontStyle(androidx.wear.protolayout.LayoutElementBuilders.FontStyle);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setLineHeight(androidx.wear.protolayout.DimensionBuilders.SpProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setMaxLines(androidx.wear.protolayout.TypeBuilders.Int32Prop);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setMaxLines(@IntRange(from=1) int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setMultilineAlignment(androidx.wear.protolayout.LayoutElementBuilders.TextAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setMultilineAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setOverflow(androidx.wear.protolayout.LayoutElementBuilders.TextOverflowProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setOverflow(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setText(androidx.wear.protolayout.TypeBuilders.StringProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setText(String);
+ }
+
+ public static final class LayoutElementBuilders.TextAlignmentProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.TextAlignmentProp.Builder {
+ ctor public LayoutElementBuilders.TextAlignmentProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextAlignmentProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextAlignmentProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.TextOverflowProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.TextOverflowProp.Builder {
+ ctor public LayoutElementBuilders.TextOverflowProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextOverflowProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextOverflowProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.VerticalAlignmentProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.VerticalAlignmentProp.Builder {
+ ctor public LayoutElementBuilders.VerticalAlignmentProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp.Builder setValue(int);
+ }
+
+ public final class ModifiersBuilders {
+ }
+
+ public static final class ModifiersBuilders.ArcModifiers {
+ method public androidx.wear.protolayout.ModifiersBuilders.Clickable? getClickable();
+ method public androidx.wear.protolayout.ModifiersBuilders.Semantics? getSemantics();
+ }
+
+ public static final class ModifiersBuilders.ArcModifiers.Builder {
+ ctor public ModifiersBuilders.ArcModifiers.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers build();
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers.Builder setClickable(androidx.wear.protolayout.ModifiersBuilders.Clickable);
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers.Builder setSemantics(androidx.wear.protolayout.ModifiersBuilders.Semantics);
+ }
+
+ public static final class ModifiersBuilders.Background {
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp? getColor();
+ method public androidx.wear.protolayout.ModifiersBuilders.Corner? getCorner();
+ }
+
+ public static final class ModifiersBuilders.Background.Builder {
+ ctor public ModifiersBuilders.Background.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Background build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Background.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Background.Builder setCorner(androidx.wear.protolayout.ModifiersBuilders.Corner);
+ }
+
+ public static final class ModifiersBuilders.Border {
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp? getColor();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getWidth();
+ }
+
+ public static final class ModifiersBuilders.Border.Builder {
+ ctor public ModifiersBuilders.Border.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Border build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Border.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Border.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ }
+
+ public static final class ModifiersBuilders.Clickable {
+ method public String getId();
+ method public androidx.wear.protolayout.ActionBuilders.Action? getOnClick();
+ }
+
+ public static final class ModifiersBuilders.Clickable.Builder {
+ ctor public ModifiersBuilders.Clickable.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Clickable build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Clickable.Builder setId(String);
+ method public androidx.wear.protolayout.ModifiersBuilders.Clickable.Builder setOnClick(androidx.wear.protolayout.ActionBuilders.Action);
+ }
+
+ public static final class ModifiersBuilders.Corner {
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getRadius();
+ }
+
+ public static final class ModifiersBuilders.Corner.Builder {
+ ctor public ModifiersBuilders.Corner.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Corner build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Corner.Builder setRadius(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ }
+
+ public static final class ModifiersBuilders.ElementMetadata {
+ method public byte[] getTagData();
+ }
+
+ public static final class ModifiersBuilders.ElementMetadata.Builder {
+ ctor public ModifiersBuilders.ElementMetadata.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.ElementMetadata build();
+ method public androidx.wear.protolayout.ModifiersBuilders.ElementMetadata.Builder setTagData(byte[]);
+ }
+
+ public static final class ModifiersBuilders.Modifiers {
+ method public androidx.wear.protolayout.ModifiersBuilders.Background? getBackground();
+ method public androidx.wear.protolayout.ModifiersBuilders.Border? getBorder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Clickable? getClickable();
+ method public androidx.wear.protolayout.ModifiersBuilders.ElementMetadata? getMetadata();
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding? getPadding();
+ method public androidx.wear.protolayout.ModifiersBuilders.Semantics? getSemantics();
+ }
+
+ public static final class ModifiersBuilders.Modifiers.Builder {
+ ctor public ModifiersBuilders.Modifiers.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setBackground(androidx.wear.protolayout.ModifiersBuilders.Background);
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setBorder(androidx.wear.protolayout.ModifiersBuilders.Border);
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setClickable(androidx.wear.protolayout.ModifiersBuilders.Clickable);
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setMetadata(androidx.wear.protolayout.ModifiersBuilders.ElementMetadata);
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setPadding(androidx.wear.protolayout.ModifiersBuilders.Padding);
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setSemantics(androidx.wear.protolayout.ModifiersBuilders.Semantics);
+ }
+
+ public static final class ModifiersBuilders.Padding {
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getBottom();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getEnd();
+ method public androidx.wear.protolayout.TypeBuilders.BoolProp? getRtlAware();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getStart();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getTop();
+ }
+
+ public static final class ModifiersBuilders.Padding.Builder {
+ ctor public ModifiersBuilders.Padding.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setAll(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setBottom(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setEnd(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setRtlAware(androidx.wear.protolayout.TypeBuilders.BoolProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setRtlAware(boolean);
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setStart(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setTop(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ }
+
+ public static final class ModifiersBuilders.Semantics {
+ method public String getContentDescription();
+ }
+
+ public static final class ModifiersBuilders.Semantics.Builder {
+ ctor public ModifiersBuilders.Semantics.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Semantics build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Semantics.Builder setContentDescription(String);
+ }
+
+ public static final class ModifiersBuilders.SpanModifiers {
+ method public androidx.wear.protolayout.ModifiersBuilders.Clickable? getClickable();
+ }
+
+ public static final class ModifiersBuilders.SpanModifiers.Builder {
+ ctor public ModifiersBuilders.SpanModifiers.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.SpanModifiers build();
+ method public androidx.wear.protolayout.ModifiersBuilders.SpanModifiers.Builder setClickable(androidx.wear.protolayout.ModifiersBuilders.Clickable);
+ }
+
+ public final class ResourceBuilders {
+ field public static final int IMAGE_FORMAT_RGB_565 = 1; // 0x1
+ field public static final int IMAGE_FORMAT_UNDEFINED = 0; // 0x0
+ }
+
+ public static final class ResourceBuilders.AndroidImageResourceByResId {
+ method @DrawableRes public int getResourceId();
+ }
+
+ public static final class ResourceBuilders.AndroidImageResourceByResId.Builder {
+ ctor public ResourceBuilders.AndroidImageResourceByResId.Builder();
+ method public androidx.wear.protolayout.ResourceBuilders.AndroidImageResourceByResId build();
+ method public androidx.wear.protolayout.ResourceBuilders.AndroidImageResourceByResId.Builder setResourceId(@DrawableRes int);
+ }
+
+ public static final class ResourceBuilders.ImageResource {
+ method public androidx.wear.protolayout.ResourceBuilders.AndroidImageResourceByResId? getAndroidResourceByResId();
+ method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource? getInlineResource();
+ }
+
+ public static final class ResourceBuilders.ImageResource.Builder {
+ ctor public ResourceBuilders.ImageResource.Builder();
+ method public androidx.wear.protolayout.ResourceBuilders.ImageResource build();
+ method public androidx.wear.protolayout.ResourceBuilders.ImageResource.Builder setAndroidResourceByResId(androidx.wear.protolayout.ResourceBuilders.AndroidImageResourceByResId);
+ method public androidx.wear.protolayout.ResourceBuilders.ImageResource.Builder setInlineResource(androidx.wear.protolayout.ResourceBuilders.InlineImageResource);
+ }
+
+ public static final class ResourceBuilders.InlineImageResource {
+ method public byte[] getData();
+ method public int getFormat();
+ method @Dimension(unit=androidx.annotation.Dimension.PX) public int getHeightPx();
+ method @Dimension(unit=androidx.annotation.Dimension.PX) public int getWidthPx();
+ }
+
+ public static final class ResourceBuilders.InlineImageResource.Builder {
+ ctor public ResourceBuilders.InlineImageResource.Builder();
+ method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource build();
+ method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource.Builder setData(byte[]);
+ method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource.Builder setFormat(int);
+ method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource.Builder setHeightPx(@Dimension(unit=androidx.annotation.Dimension.PX) int);
+ method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource.Builder setWidthPx(@Dimension(unit=androidx.annotation.Dimension.PX) int);
+ }
+
+ public static final class ResourceBuilders.Resources {
+ method public java.util.Map<java.lang.String!,androidx.wear.protolayout.ResourceBuilders.ImageResource!> getIdToImageMapping();
+ method public String getVersion();
+ }
+
+ public static final class ResourceBuilders.Resources.Builder {
+ ctor public ResourceBuilders.Resources.Builder();
+ method public androidx.wear.protolayout.ResourceBuilders.Resources.Builder addIdToImageMapping(String, androidx.wear.protolayout.ResourceBuilders.ImageResource);
+ method public androidx.wear.protolayout.ResourceBuilders.Resources build();
+ method public androidx.wear.protolayout.ResourceBuilders.Resources.Builder setVersion(String);
+ }
+
+ public final class StateBuilders {
+ }
+
+ public static final class StateBuilders.State {
+ method public String getLastClickableId();
+ }
+
+ public static final class StateBuilders.State.Builder {
+ ctor public StateBuilders.State.Builder();
+ method public androidx.wear.protolayout.StateBuilders.State build();
+ }
+
+ public final class TimelineBuilders {
+ }
+
+ public static final class TimelineBuilders.TimeInterval {
+ method public long getEndMillis();
+ method public long getStartMillis();
+ }
+
+ public static final class TimelineBuilders.TimeInterval.Builder {
+ ctor public TimelineBuilders.TimeInterval.Builder();
+ method public androidx.wear.protolayout.TimelineBuilders.TimeInterval build();
+ method public androidx.wear.protolayout.TimelineBuilders.TimeInterval.Builder setEndMillis(long);
+ method public androidx.wear.protolayout.TimelineBuilders.TimeInterval.Builder setStartMillis(long);
+ }
+
+ public static final class TimelineBuilders.Timeline {
+ method public static androidx.wear.protolayout.TimelineBuilders.Timeline fromLayoutElement(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public java.util.List<androidx.wear.protolayout.TimelineBuilders.TimelineEntry!> getTimelineEntries();
+ }
+
+ public static final class TimelineBuilders.Timeline.Builder {
+ ctor public TimelineBuilders.Timeline.Builder();
+ method public androidx.wear.protolayout.TimelineBuilders.Timeline.Builder addTimelineEntry(androidx.wear.protolayout.TimelineBuilders.TimelineEntry);
+ method public androidx.wear.protolayout.TimelineBuilders.Timeline build();
+ }
+
+ public static final class TimelineBuilders.TimelineEntry {
+ method public static androidx.wear.protolayout.TimelineBuilders.TimelineEntry fromLayoutElement(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Layout? getLayout();
+ method public androidx.wear.protolayout.TimelineBuilders.TimeInterval? getValidity();
+ }
+
+ public static final class TimelineBuilders.TimelineEntry.Builder {
+ ctor public TimelineBuilders.TimelineEntry.Builder();
+ method public androidx.wear.protolayout.TimelineBuilders.TimelineEntry build();
+ method public androidx.wear.protolayout.TimelineBuilders.TimelineEntry.Builder setLayout(androidx.wear.protolayout.LayoutElementBuilders.Layout);
+ method public androidx.wear.protolayout.TimelineBuilders.TimelineEntry.Builder setValidity(androidx.wear.protolayout.TimelineBuilders.TimeInterval);
+ }
+
+ public final class TypeBuilders {
+ }
+
+ public static final class TypeBuilders.BoolProp {
+ method public boolean getValue();
+ }
+
+ public static final class TypeBuilders.BoolProp.Builder {
+ ctor public TypeBuilders.BoolProp.Builder();
+ method public androidx.wear.protolayout.TypeBuilders.BoolProp build();
+ method public androidx.wear.protolayout.TypeBuilders.BoolProp.Builder setValue(boolean);
+ }
+
+ public static final class TypeBuilders.FloatProp {
+ method public float getValue();
+ }
+
+ public static final class TypeBuilders.FloatProp.Builder {
+ ctor public TypeBuilders.FloatProp.Builder();
+ method public androidx.wear.protolayout.TypeBuilders.FloatProp build();
+ method public androidx.wear.protolayout.TypeBuilders.FloatProp.Builder setValue(float);
+ }
+
+ public static final class TypeBuilders.Int32Prop {
+ method public int getValue();
+ }
+
+ public static final class TypeBuilders.Int32Prop.Builder {
+ ctor public TypeBuilders.Int32Prop.Builder();
+ method public androidx.wear.protolayout.TypeBuilders.Int32Prop build();
+ method public androidx.wear.protolayout.TypeBuilders.Int32Prop.Builder setValue(int);
+ }
+
+ public static final class TypeBuilders.StringProp {
+ method public String getValue();
+ }
+
+ public static final class TypeBuilders.StringProp.Builder {
+ ctor public TypeBuilders.StringProp.Builder();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp build();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp.Builder setValue(String);
+ }
+
+}
+
diff --git a/wear/protolayout/protolayout/api/public_plus_experimental_current.txt b/wear/protolayout/protolayout/api/public_plus_experimental_current.txt
index e6f50d0..f69773d 100644
--- a/wear/protolayout/protolayout/api/public_plus_experimental_current.txt
+++ b/wear/protolayout/protolayout/api/public_plus_experimental_current.txt
@@ -1 +1,1002 @@
// Signature format: 4.0
+package androidx.wear.protolayout {
+
+ public final class ActionBuilders {
+ method public static androidx.wear.protolayout.ActionBuilders.AndroidBooleanExtra booleanExtra(boolean);
+ method public static androidx.wear.protolayout.ActionBuilders.AndroidDoubleExtra doubleExtra(double);
+ method public static androidx.wear.protolayout.ActionBuilders.AndroidIntExtra intExtra(int);
+ method public static androidx.wear.protolayout.ActionBuilders.AndroidLongExtra longExtra(long);
+ method public static androidx.wear.protolayout.ActionBuilders.AndroidStringExtra stringExtra(String);
+ }
+
+ public static interface ActionBuilders.Action {
+ }
+
+ public static interface ActionBuilders.Action.Builder {
+ method public androidx.wear.protolayout.ActionBuilders.Action build();
+ }
+
+ public static final class ActionBuilders.AndroidActivity {
+ method public String getClassName();
+ method public java.util.Map<java.lang.String!,androidx.wear.protolayout.ActionBuilders.AndroidExtra!> getKeyToExtraMapping();
+ method public String getPackageName();
+ }
+
+ public static final class ActionBuilders.AndroidActivity.Builder {
+ ctor public ActionBuilders.AndroidActivity.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidActivity.Builder addKeyToExtraMapping(String, androidx.wear.protolayout.ActionBuilders.AndroidExtra);
+ method public androidx.wear.protolayout.ActionBuilders.AndroidActivity build();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidActivity.Builder setClassName(String);
+ method public androidx.wear.protolayout.ActionBuilders.AndroidActivity.Builder setPackageName(String);
+ }
+
+ public static final class ActionBuilders.AndroidBooleanExtra implements androidx.wear.protolayout.ActionBuilders.AndroidExtra {
+ method public boolean getValue();
+ }
+
+ public static final class ActionBuilders.AndroidBooleanExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ ctor public ActionBuilders.AndroidBooleanExtra.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidBooleanExtra build();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidBooleanExtra.Builder setValue(boolean);
+ }
+
+ public static final class ActionBuilders.AndroidDoubleExtra implements androidx.wear.protolayout.ActionBuilders.AndroidExtra {
+ method public double getValue();
+ }
+
+ public static final class ActionBuilders.AndroidDoubleExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ ctor public ActionBuilders.AndroidDoubleExtra.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidDoubleExtra build();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidDoubleExtra.Builder setValue(double);
+ }
+
+ public static interface ActionBuilders.AndroidExtra {
+ }
+
+ public static interface ActionBuilders.AndroidExtra.Builder {
+ method public androidx.wear.protolayout.ActionBuilders.AndroidExtra build();
+ }
+
+ public static final class ActionBuilders.AndroidIntExtra implements androidx.wear.protolayout.ActionBuilders.AndroidExtra {
+ method public int getValue();
+ }
+
+ public static final class ActionBuilders.AndroidIntExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ ctor public ActionBuilders.AndroidIntExtra.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidIntExtra build();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidIntExtra.Builder setValue(int);
+ }
+
+ public static final class ActionBuilders.AndroidLongExtra implements androidx.wear.protolayout.ActionBuilders.AndroidExtra {
+ method public long getValue();
+ }
+
+ public static final class ActionBuilders.AndroidLongExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ ctor public ActionBuilders.AndroidLongExtra.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidLongExtra build();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidLongExtra.Builder setValue(long);
+ }
+
+ public static final class ActionBuilders.AndroidStringExtra implements androidx.wear.protolayout.ActionBuilders.AndroidExtra {
+ method public String getValue();
+ }
+
+ public static final class ActionBuilders.AndroidStringExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ ctor public ActionBuilders.AndroidStringExtra.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidStringExtra build();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidStringExtra.Builder setValue(String);
+ }
+
+ public static final class ActionBuilders.LaunchAction implements androidx.wear.protolayout.ActionBuilders.Action {
+ method public androidx.wear.protolayout.ActionBuilders.AndroidActivity? getAndroidActivity();
+ }
+
+ public static final class ActionBuilders.LaunchAction.Builder implements androidx.wear.protolayout.ActionBuilders.Action.Builder {
+ ctor public ActionBuilders.LaunchAction.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.LaunchAction build();
+ method public androidx.wear.protolayout.ActionBuilders.LaunchAction.Builder setAndroidActivity(androidx.wear.protolayout.ActionBuilders.AndroidActivity);
+ }
+
+ public static final class ActionBuilders.LoadAction implements androidx.wear.protolayout.ActionBuilders.Action {
+ method public androidx.wear.protolayout.StateBuilders.State? getRequestState();
+ }
+
+ public static final class ActionBuilders.LoadAction.Builder implements androidx.wear.protolayout.ActionBuilders.Action.Builder {
+ ctor public ActionBuilders.LoadAction.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.LoadAction build();
+ method public androidx.wear.protolayout.ActionBuilders.LoadAction.Builder setRequestState(androidx.wear.protolayout.StateBuilders.State);
+ }
+
+ public final class ColorBuilders {
+ method public static androidx.wear.protolayout.ColorBuilders.ColorProp argb(@ColorInt int);
+ }
+
+ public static final class ColorBuilders.ColorProp {
+ method @ColorInt public int getArgb();
+ }
+
+ public static final class ColorBuilders.ColorProp.Builder {
+ ctor public ColorBuilders.ColorProp.Builder();
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp build();
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp.Builder setArgb(@ColorInt int);
+ }
+
+ public final class DeviceParametersBuilders {
+ field public static final int DEVICE_PLATFORM_UNDEFINED = 0; // 0x0
+ field public static final int DEVICE_PLATFORM_WEAR_OS = 1; // 0x1
+ field public static final int SCREEN_SHAPE_RECT = 2; // 0x2
+ field public static final int SCREEN_SHAPE_ROUND = 1; // 0x1
+ field public static final int SCREEN_SHAPE_UNDEFINED = 0; // 0x0
+ }
+
+ public static final class DeviceParametersBuilders.DeviceParameters {
+ method public int getDevicePlatform();
+ method @FloatRange(from=0.0, fromInclusive=false, toInclusive=false) public float getScreenDensity();
+ method @Dimension(unit=androidx.annotation.Dimension.DP) public int getScreenHeightDp();
+ method public int getScreenShape();
+ method @Dimension(unit=androidx.annotation.Dimension.DP) public int getScreenWidthDp();
+ }
+
+ public static final class DeviceParametersBuilders.DeviceParameters.Builder {
+ ctor public DeviceParametersBuilders.DeviceParameters.Builder();
+ method public androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters build();
+ method public androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters.Builder setDevicePlatform(int);
+ method public androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters.Builder setScreenDensity(@FloatRange(from=0.0, fromInclusive=false, toInclusive=false) float);
+ method public androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters.Builder setScreenHeightDp(@Dimension(unit=androidx.annotation.Dimension.DP) int);
+ method public androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters.Builder setScreenShape(int);
+ method public androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters.Builder setScreenWidthDp(@Dimension(unit=androidx.annotation.Dimension.DP) int);
+ }
+
+ public final class DimensionBuilders {
+ method public static androidx.wear.protolayout.DimensionBuilders.DegreesProp degrees(float);
+ method public static androidx.wear.protolayout.DimensionBuilders.DpProp dp(@Dimension(unit=androidx.annotation.Dimension.DP) float);
+ method public static androidx.wear.protolayout.DimensionBuilders.EmProp em(int);
+ method public static androidx.wear.protolayout.DimensionBuilders.EmProp em(float);
+ method public static androidx.wear.protolayout.DimensionBuilders.ExpandedDimensionProp expand();
+ method public static androidx.wear.protolayout.DimensionBuilders.SpProp sp(@Dimension(unit=androidx.annotation.Dimension.SP) float);
+ method public static androidx.wear.protolayout.DimensionBuilders.WrappedDimensionProp wrap();
+ }
+
+ public static interface DimensionBuilders.ContainerDimension {
+ }
+
+ public static interface DimensionBuilders.ContainerDimension.Builder {
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension build();
+ }
+
+ public static final class DimensionBuilders.DegreesProp {
+ method public float getValue();
+ }
+
+ public static final class DimensionBuilders.DegreesProp.Builder {
+ ctor public DimensionBuilders.DegreesProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.DegreesProp build();
+ method public androidx.wear.protolayout.DimensionBuilders.DegreesProp.Builder setValue(float);
+ }
+
+ public static final class DimensionBuilders.DpProp implements androidx.wear.protolayout.DimensionBuilders.ContainerDimension androidx.wear.protolayout.DimensionBuilders.ImageDimension androidx.wear.protolayout.DimensionBuilders.SpacerDimension {
+ method @Dimension(unit=androidx.annotation.Dimension.DP) public float getValue();
+ }
+
+ public static final class DimensionBuilders.DpProp.Builder implements androidx.wear.protolayout.DimensionBuilders.ContainerDimension.Builder androidx.wear.protolayout.DimensionBuilders.ImageDimension.Builder androidx.wear.protolayout.DimensionBuilders.SpacerDimension.Builder {
+ ctor public DimensionBuilders.DpProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp build();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp.Builder setValue(@Dimension(unit=androidx.annotation.Dimension.DP) float);
+ }
+
+ public static final class DimensionBuilders.EmProp {
+ method public float getValue();
+ }
+
+ public static final class DimensionBuilders.EmProp.Builder {
+ ctor public DimensionBuilders.EmProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.EmProp build();
+ method public androidx.wear.protolayout.DimensionBuilders.EmProp.Builder setValue(float);
+ }
+
+ public static final class DimensionBuilders.ExpandedDimensionProp implements androidx.wear.protolayout.DimensionBuilders.ContainerDimension androidx.wear.protolayout.DimensionBuilders.ImageDimension {
+ }
+
+ public static final class DimensionBuilders.ExpandedDimensionProp.Builder implements androidx.wear.protolayout.DimensionBuilders.ContainerDimension.Builder androidx.wear.protolayout.DimensionBuilders.ImageDimension.Builder {
+ ctor public DimensionBuilders.ExpandedDimensionProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.ExpandedDimensionProp build();
+ }
+
+ public static interface DimensionBuilders.ImageDimension {
+ }
+
+ public static interface DimensionBuilders.ImageDimension.Builder {
+ method public androidx.wear.protolayout.DimensionBuilders.ImageDimension build();
+ }
+
+ public static final class DimensionBuilders.ProportionalDimensionProp implements androidx.wear.protolayout.DimensionBuilders.ImageDimension {
+ method @IntRange(from=0) public int getAspectRatioHeight();
+ method @IntRange(from=0) public int getAspectRatioWidth();
+ }
+
+ public static final class DimensionBuilders.ProportionalDimensionProp.Builder implements androidx.wear.protolayout.DimensionBuilders.ImageDimension.Builder {
+ ctor public DimensionBuilders.ProportionalDimensionProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.ProportionalDimensionProp build();
+ method public androidx.wear.protolayout.DimensionBuilders.ProportionalDimensionProp.Builder setAspectRatioHeight(@IntRange(from=0) int);
+ method public androidx.wear.protolayout.DimensionBuilders.ProportionalDimensionProp.Builder setAspectRatioWidth(@IntRange(from=0) int);
+ }
+
+ public static final class DimensionBuilders.SpProp {
+ method @Dimension(unit=androidx.annotation.Dimension.SP) public float getValue();
+ }
+
+ public static final class DimensionBuilders.SpProp.Builder {
+ ctor public DimensionBuilders.SpProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.SpProp build();
+ method public androidx.wear.protolayout.DimensionBuilders.SpProp.Builder setValue(@Dimension(unit=androidx.annotation.Dimension.SP) float);
+ }
+
+ public static interface DimensionBuilders.SpacerDimension {
+ }
+
+ public static interface DimensionBuilders.SpacerDimension.Builder {
+ method public androidx.wear.protolayout.DimensionBuilders.SpacerDimension build();
+ }
+
+ public static final class DimensionBuilders.WrappedDimensionProp implements androidx.wear.protolayout.DimensionBuilders.ContainerDimension {
+ }
+
+ public static final class DimensionBuilders.WrappedDimensionProp.Builder implements androidx.wear.protolayout.DimensionBuilders.ContainerDimension.Builder {
+ ctor public DimensionBuilders.WrappedDimensionProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.WrappedDimensionProp build();
+ }
+
+ public final class LayoutElementBuilders {
+ field public static final int ARC_ANCHOR_CENTER = 2; // 0x2
+ field public static final int ARC_ANCHOR_END = 3; // 0x3
+ field public static final int ARC_ANCHOR_START = 1; // 0x1
+ field public static final int ARC_ANCHOR_UNDEFINED = 0; // 0x0
+ field public static final int CONTENT_SCALE_MODE_CROP = 2; // 0x2
+ field public static final int CONTENT_SCALE_MODE_FILL_BOUNDS = 3; // 0x3
+ field public static final int CONTENT_SCALE_MODE_FIT = 1; // 0x1
+ field public static final int CONTENT_SCALE_MODE_UNDEFINED = 0; // 0x0
+ field public static final int FONT_VARIANT_BODY = 2; // 0x2
+ field public static final int FONT_VARIANT_TITLE = 1; // 0x1
+ field public static final int FONT_VARIANT_UNDEFINED = 0; // 0x0
+ field public static final int FONT_WEIGHT_BOLD = 700; // 0x2bc
+ field @androidx.wear.protolayout.expression.ProtoLayoutExperimental public static final int FONT_WEIGHT_MEDIUM = 500; // 0x1f4
+ field public static final int FONT_WEIGHT_NORMAL = 400; // 0x190
+ field public static final int FONT_WEIGHT_UNDEFINED = 0; // 0x0
+ field public static final int HORIZONTAL_ALIGN_CENTER = 2; // 0x2
+ field public static final int HORIZONTAL_ALIGN_END = 5; // 0x5
+ field public static final int HORIZONTAL_ALIGN_LEFT = 1; // 0x1
+ field public static final int HORIZONTAL_ALIGN_RIGHT = 3; // 0x3
+ field public static final int HORIZONTAL_ALIGN_START = 4; // 0x4
+ field public static final int HORIZONTAL_ALIGN_UNDEFINED = 0; // 0x0
+ field public static final int SPAN_VERTICAL_ALIGN_BOTTOM = 1; // 0x1
+ field public static final int SPAN_VERTICAL_ALIGN_TEXT_BASELINE = 2; // 0x2
+ field public static final int SPAN_VERTICAL_ALIGN_UNDEFINED = 0; // 0x0
+ field public static final int TEXT_ALIGN_CENTER = 2; // 0x2
+ field public static final int TEXT_ALIGN_END = 3; // 0x3
+ field public static final int TEXT_ALIGN_START = 1; // 0x1
+ field public static final int TEXT_ALIGN_UNDEFINED = 0; // 0x0
+ field public static final int TEXT_OVERFLOW_ELLIPSIZE_END = 2; // 0x2
+ field public static final int TEXT_OVERFLOW_TRUNCATE = 1; // 0x1
+ field public static final int TEXT_OVERFLOW_UNDEFINED = 0; // 0x0
+ field public static final int VERTICAL_ALIGN_BOTTOM = 3; // 0x3
+ field public static final int VERTICAL_ALIGN_CENTER = 2; // 0x2
+ field public static final int VERTICAL_ALIGN_TOP = 1; // 0x1
+ field public static final int VERTICAL_ALIGN_UNDEFINED = 0; // 0x0
+ }
+
+ public static final class LayoutElementBuilders.Arc implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public androidx.wear.protolayout.DimensionBuilders.DegreesProp? getAnchorAngle();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAnchorTypeProp? getAnchorType();
+ method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement!> getContents();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp? getVerticalAlign();
+ }
+
+ public static final class LayoutElementBuilders.Arc.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Arc.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder setAnchorAngle(androidx.wear.protolayout.DimensionBuilders.DegreesProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder setAnchorType(androidx.wear.protolayout.LayoutElementBuilders.ArcAnchorTypeProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder setAnchorType(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder setVerticalAlign(androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder setVerticalAlign(int);
+ }
+
+ public static final class LayoutElementBuilders.ArcAdapter implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement {
+ method public androidx.wear.protolayout.LayoutElementBuilders.LayoutElement? getContent();
+ method public androidx.wear.protolayout.TypeBuilders.BoolProp? getRotateContents();
+ }
+
+ public static final class LayoutElementBuilders.ArcAdapter.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ ctor public LayoutElementBuilders.ArcAdapter.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAdapter build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAdapter.Builder setContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAdapter.Builder setRotateContents(androidx.wear.protolayout.TypeBuilders.BoolProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAdapter.Builder setRotateContents(boolean);
+ }
+
+ public static final class LayoutElementBuilders.ArcAnchorTypeProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.ArcAnchorTypeProp.Builder {
+ ctor public LayoutElementBuilders.ArcAnchorTypeProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAnchorTypeProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAnchorTypeProp.Builder setValue(int);
+ }
+
+ public static interface LayoutElementBuilders.ArcLayoutElement {
+ }
+
+ public static interface LayoutElementBuilders.ArcLayoutElement.Builder {
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement build();
+ }
+
+ public static final class LayoutElementBuilders.ArcLine implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement {
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp? getColor();
+ method public androidx.wear.protolayout.DimensionBuilders.DegreesProp? getLength();
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers? getModifiers();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getThickness();
+ }
+
+ public static final class LayoutElementBuilders.ArcLine.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ ctor public LayoutElementBuilders.ArcLine.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine.Builder setLength(androidx.wear.protolayout.DimensionBuilders.DegreesProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.ArcModifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine.Builder setThickness(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ }
+
+ public static final class LayoutElementBuilders.ArcSpacer implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement {
+ method public androidx.wear.protolayout.DimensionBuilders.DegreesProp? getLength();
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers? getModifiers();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getThickness();
+ }
+
+ public static final class LayoutElementBuilders.ArcSpacer.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ ctor public LayoutElementBuilders.ArcSpacer.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcSpacer build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcSpacer.Builder setLength(androidx.wear.protolayout.DimensionBuilders.DegreesProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcSpacer.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.ArcModifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcSpacer.Builder setThickness(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ }
+
+ public static final class LayoutElementBuilders.ArcText implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement {
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle? getFontStyle();
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers? getModifiers();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp? getText();
+ }
+
+ public static final class LayoutElementBuilders.ArcText.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ ctor public LayoutElementBuilders.ArcText.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcText build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcText.Builder setFontStyle(androidx.wear.protolayout.LayoutElementBuilders.FontStyle);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcText.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.ArcModifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcText.Builder setText(androidx.wear.protolayout.TypeBuilders.StringProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcText.Builder setText(String);
+ }
+
+ public static final class LayoutElementBuilders.Box implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.LayoutElement!> getContents();
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getHeight();
+ method public androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp? getHorizontalAlignment();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp? getVerticalAlignment();
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getWidth();
+ }
+
+ public static final class LayoutElementBuilders.Box.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Box.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setHorizontalAlignment(androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setHorizontalAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setVerticalAlignment(androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setVerticalAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
+ }
+
+ public static final class LayoutElementBuilders.ColorFilter {
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp? getTint();
+ }
+
+ public static final class LayoutElementBuilders.ColorFilter.Builder {
+ ctor public LayoutElementBuilders.ColorFilter.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ColorFilter build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ColorFilter.Builder setTint(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ }
+
+ public static final class LayoutElementBuilders.Column implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.LayoutElement!> getContents();
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getHeight();
+ method public androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp? getHorizontalAlignment();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getWidth();
+ }
+
+ public static final class LayoutElementBuilders.Column.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Column.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder setHorizontalAlignment(androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder setHorizontalAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
+ }
+
+ public static final class LayoutElementBuilders.ContentScaleModeProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.ContentScaleModeProp.Builder {
+ ctor public LayoutElementBuilders.ContentScaleModeProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ContentScaleModeProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ContentScaleModeProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.FontStyle {
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp? getColor();
+ method public androidx.wear.protolayout.TypeBuilders.BoolProp? getItalic();
+ method public androidx.wear.protolayout.DimensionBuilders.EmProp? getLetterSpacing();
+ method public androidx.wear.protolayout.DimensionBuilders.SpProp? getSize();
+ method public androidx.wear.protolayout.TypeBuilders.BoolProp? getUnderline();
+ method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.LayoutElementBuilders.FontVariantProp? getVariant();
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontWeightProp? getWeight();
+ }
+
+ public static final class LayoutElementBuilders.FontStyle.Builder {
+ ctor public LayoutElementBuilders.FontStyle.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setItalic(androidx.wear.protolayout.TypeBuilders.BoolProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setItalic(boolean);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setLetterSpacing(androidx.wear.protolayout.DimensionBuilders.EmProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setSize(androidx.wear.protolayout.DimensionBuilders.SpProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setUnderline(androidx.wear.protolayout.TypeBuilders.BoolProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setUnderline(boolean);
+ method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setVariant(androidx.wear.protolayout.LayoutElementBuilders.FontVariantProp);
+ method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setVariant(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setWeight(androidx.wear.protolayout.LayoutElementBuilders.FontWeightProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setWeight(int);
+ }
+
+ public static class LayoutElementBuilders.FontStyles {
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder body1(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder body2(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder button(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder caption1(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder caption2(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder display1(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder display2(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder display3(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder title1(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder title2(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder title3(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ }
+
+ @androidx.wear.protolayout.expression.ProtoLayoutExperimental public static final class LayoutElementBuilders.FontVariantProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.FontVariantProp.Builder {
+ ctor public LayoutElementBuilders.FontVariantProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontVariantProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontVariantProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.FontWeightProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.FontWeightProp.Builder {
+ ctor public LayoutElementBuilders.FontWeightProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontWeightProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontWeightProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.HorizontalAlignmentProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.HorizontalAlignmentProp.Builder {
+ ctor public LayoutElementBuilders.HorizontalAlignmentProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.Image implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public androidx.wear.protolayout.LayoutElementBuilders.ColorFilter? getColorFilter();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ContentScaleModeProp? getContentScaleMode();
+ method public androidx.wear.protolayout.DimensionBuilders.ImageDimension? getHeight();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp? getResourceId();
+ method public androidx.wear.protolayout.DimensionBuilders.ImageDimension? getWidth();
+ }
+
+ public static final class LayoutElementBuilders.Image.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Image.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setColorFilter(androidx.wear.protolayout.LayoutElementBuilders.ColorFilter);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setContentScaleMode(androidx.wear.protolayout.LayoutElementBuilders.ContentScaleModeProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setContentScaleMode(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.ImageDimension);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setResourceId(androidx.wear.protolayout.TypeBuilders.StringProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setResourceId(String);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.ImageDimension);
+ }
+
+ public static final class LayoutElementBuilders.Layout {
+ method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public static androidx.wear.protolayout.LayoutElementBuilders.Layout? fromByteArray(byte[]);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.Layout fromLayoutElement(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.LayoutElement? getRoot();
+ method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public byte[] toByteArray();
+ }
+
+ public static final class LayoutElementBuilders.Layout.Builder {
+ ctor public LayoutElementBuilders.Layout.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Layout build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Layout.Builder setRoot(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ }
+
+ public static interface LayoutElementBuilders.LayoutElement {
+ }
+
+ public static interface LayoutElementBuilders.LayoutElement.Builder {
+ method public androidx.wear.protolayout.LayoutElementBuilders.LayoutElement build();
+ }
+
+ public static final class LayoutElementBuilders.Row implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.LayoutElement!> getContents();
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getHeight();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp? getVerticalAlignment();
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getWidth();
+ }
+
+ public static final class LayoutElementBuilders.Row.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Row.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder setVerticalAlignment(androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder setVerticalAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
+ }
+
+ public static final class LayoutElementBuilders.Spacer implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public androidx.wear.protolayout.DimensionBuilders.SpacerDimension? getHeight();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.DimensionBuilders.SpacerDimension? getWidth();
+ }
+
+ public static final class LayoutElementBuilders.Spacer.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Spacer.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spacer build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spacer.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.SpacerDimension);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spacer.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spacer.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.SpacerDimension);
+ }
+
+ public static interface LayoutElementBuilders.Span {
+ }
+
+ public static interface LayoutElementBuilders.Span.Builder {
+ method public androidx.wear.protolayout.LayoutElementBuilders.Span build();
+ }
+
+ public static final class LayoutElementBuilders.SpanImage implements androidx.wear.protolayout.LayoutElementBuilders.Span {
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanVerticalAlignmentProp? getAlignment();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getHeight();
+ method public androidx.wear.protolayout.ModifiersBuilders.SpanModifiers? getModifiers();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp? getResourceId();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getWidth();
+ }
+
+ public static final class LayoutElementBuilders.SpanImage.Builder implements androidx.wear.protolayout.LayoutElementBuilders.Span.Builder {
+ ctor public LayoutElementBuilders.SpanImage.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setAlignment(androidx.wear.protolayout.LayoutElementBuilders.SpanVerticalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.SpanModifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setResourceId(androidx.wear.protolayout.TypeBuilders.StringProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setResourceId(String);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ }
+
+ public static final class LayoutElementBuilders.SpanText implements androidx.wear.protolayout.LayoutElementBuilders.Span {
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle? getFontStyle();
+ method public androidx.wear.protolayout.ModifiersBuilders.SpanModifiers? getModifiers();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp? getText();
+ }
+
+ public static final class LayoutElementBuilders.SpanText.Builder implements androidx.wear.protolayout.LayoutElementBuilders.Span.Builder {
+ ctor public LayoutElementBuilders.SpanText.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanText build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanText.Builder setFontStyle(androidx.wear.protolayout.LayoutElementBuilders.FontStyle);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanText.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.SpanModifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanText.Builder setText(androidx.wear.protolayout.TypeBuilders.StringProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanText.Builder setText(String);
+ }
+
+ public static final class LayoutElementBuilders.SpanVerticalAlignmentProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.SpanVerticalAlignmentProp.Builder {
+ ctor public LayoutElementBuilders.SpanVerticalAlignmentProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanVerticalAlignmentProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanVerticalAlignmentProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.Spannable implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public androidx.wear.protolayout.DimensionBuilders.SpProp? getLineHeight();
+ method public androidx.wear.protolayout.TypeBuilders.Int32Prop? getMaxLines();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp? getMultilineAlignment();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextOverflowProp? getOverflow();
+ method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.Span!> getSpans();
+ }
+
+ public static final class LayoutElementBuilders.Spannable.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Spannable.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder addSpan(androidx.wear.protolayout.LayoutElementBuilders.Span);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setLineHeight(androidx.wear.protolayout.DimensionBuilders.SpProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setMaxLines(androidx.wear.protolayout.TypeBuilders.Int32Prop);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setMaxLines(@IntRange(from=1) int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setMultilineAlignment(androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setMultilineAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setOverflow(androidx.wear.protolayout.LayoutElementBuilders.TextOverflowProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setOverflow(int);
+ }
+
+ public static final class LayoutElementBuilders.Text implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle? getFontStyle();
+ method public androidx.wear.protolayout.DimensionBuilders.SpProp? getLineHeight();
+ method public androidx.wear.protolayout.TypeBuilders.Int32Prop? getMaxLines();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextAlignmentProp? getMultilineAlignment();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextOverflowProp? getOverflow();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp? getText();
+ }
+
+ public static final class LayoutElementBuilders.Text.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Text.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setFontStyle(androidx.wear.protolayout.LayoutElementBuilders.FontStyle);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setLineHeight(androidx.wear.protolayout.DimensionBuilders.SpProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setMaxLines(androidx.wear.protolayout.TypeBuilders.Int32Prop);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setMaxLines(@IntRange(from=1) int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setMultilineAlignment(androidx.wear.protolayout.LayoutElementBuilders.TextAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setMultilineAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setOverflow(androidx.wear.protolayout.LayoutElementBuilders.TextOverflowProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setOverflow(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setText(androidx.wear.protolayout.TypeBuilders.StringProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setText(String);
+ }
+
+ public static final class LayoutElementBuilders.TextAlignmentProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.TextAlignmentProp.Builder {
+ ctor public LayoutElementBuilders.TextAlignmentProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextAlignmentProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextAlignmentProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.TextOverflowProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.TextOverflowProp.Builder {
+ ctor public LayoutElementBuilders.TextOverflowProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextOverflowProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextOverflowProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.VerticalAlignmentProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.VerticalAlignmentProp.Builder {
+ ctor public LayoutElementBuilders.VerticalAlignmentProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp.Builder setValue(int);
+ }
+
+ public final class ModifiersBuilders {
+ }
+
+ public static final class ModifiersBuilders.ArcModifiers {
+ method public androidx.wear.protolayout.ModifiersBuilders.Clickable? getClickable();
+ method public androidx.wear.protolayout.ModifiersBuilders.Semantics? getSemantics();
+ }
+
+ public static final class ModifiersBuilders.ArcModifiers.Builder {
+ ctor public ModifiersBuilders.ArcModifiers.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers build();
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers.Builder setClickable(androidx.wear.protolayout.ModifiersBuilders.Clickable);
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers.Builder setSemantics(androidx.wear.protolayout.ModifiersBuilders.Semantics);
+ }
+
+ public static final class ModifiersBuilders.Background {
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp? getColor();
+ method public androidx.wear.protolayout.ModifiersBuilders.Corner? getCorner();
+ }
+
+ public static final class ModifiersBuilders.Background.Builder {
+ ctor public ModifiersBuilders.Background.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Background build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Background.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Background.Builder setCorner(androidx.wear.protolayout.ModifiersBuilders.Corner);
+ }
+
+ public static final class ModifiersBuilders.Border {
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp? getColor();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getWidth();
+ }
+
+ public static final class ModifiersBuilders.Border.Builder {
+ ctor public ModifiersBuilders.Border.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Border build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Border.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Border.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ }
+
+ public static final class ModifiersBuilders.Clickable {
+ method public String getId();
+ method public androidx.wear.protolayout.ActionBuilders.Action? getOnClick();
+ }
+
+ public static final class ModifiersBuilders.Clickable.Builder {
+ ctor public ModifiersBuilders.Clickable.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Clickable build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Clickable.Builder setId(String);
+ method public androidx.wear.protolayout.ModifiersBuilders.Clickable.Builder setOnClick(androidx.wear.protolayout.ActionBuilders.Action);
+ }
+
+ public static final class ModifiersBuilders.Corner {
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getRadius();
+ }
+
+ public static final class ModifiersBuilders.Corner.Builder {
+ ctor public ModifiersBuilders.Corner.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Corner build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Corner.Builder setRadius(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ }
+
+ public static final class ModifiersBuilders.ElementMetadata {
+ method public byte[] getTagData();
+ }
+
+ public static final class ModifiersBuilders.ElementMetadata.Builder {
+ ctor public ModifiersBuilders.ElementMetadata.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.ElementMetadata build();
+ method public androidx.wear.protolayout.ModifiersBuilders.ElementMetadata.Builder setTagData(byte[]);
+ }
+
+ public static final class ModifiersBuilders.Modifiers {
+ method public androidx.wear.protolayout.ModifiersBuilders.Background? getBackground();
+ method public androidx.wear.protolayout.ModifiersBuilders.Border? getBorder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Clickable? getClickable();
+ method public androidx.wear.protolayout.ModifiersBuilders.ElementMetadata? getMetadata();
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding? getPadding();
+ method public androidx.wear.protolayout.ModifiersBuilders.Semantics? getSemantics();
+ }
+
+ public static final class ModifiersBuilders.Modifiers.Builder {
+ ctor public ModifiersBuilders.Modifiers.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setBackground(androidx.wear.protolayout.ModifiersBuilders.Background);
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setBorder(androidx.wear.protolayout.ModifiersBuilders.Border);
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setClickable(androidx.wear.protolayout.ModifiersBuilders.Clickable);
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setMetadata(androidx.wear.protolayout.ModifiersBuilders.ElementMetadata);
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setPadding(androidx.wear.protolayout.ModifiersBuilders.Padding);
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setSemantics(androidx.wear.protolayout.ModifiersBuilders.Semantics);
+ }
+
+ public static final class ModifiersBuilders.Padding {
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getBottom();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getEnd();
+ method public androidx.wear.protolayout.TypeBuilders.BoolProp? getRtlAware();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getStart();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getTop();
+ }
+
+ public static final class ModifiersBuilders.Padding.Builder {
+ ctor public ModifiersBuilders.Padding.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setAll(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setBottom(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setEnd(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setRtlAware(androidx.wear.protolayout.TypeBuilders.BoolProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setRtlAware(boolean);
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setStart(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setTop(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ }
+
+ public static final class ModifiersBuilders.Semantics {
+ method public String getContentDescription();
+ }
+
+ public static final class ModifiersBuilders.Semantics.Builder {
+ ctor public ModifiersBuilders.Semantics.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Semantics build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Semantics.Builder setContentDescription(String);
+ }
+
+ public static final class ModifiersBuilders.SpanModifiers {
+ method public androidx.wear.protolayout.ModifiersBuilders.Clickable? getClickable();
+ }
+
+ public static final class ModifiersBuilders.SpanModifiers.Builder {
+ ctor public ModifiersBuilders.SpanModifiers.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.SpanModifiers build();
+ method public androidx.wear.protolayout.ModifiersBuilders.SpanModifiers.Builder setClickable(androidx.wear.protolayout.ModifiersBuilders.Clickable);
+ }
+
+ public final class ResourceBuilders {
+ field public static final int IMAGE_FORMAT_RGB_565 = 1; // 0x1
+ field public static final int IMAGE_FORMAT_UNDEFINED = 0; // 0x0
+ }
+
+ public static final class ResourceBuilders.AndroidImageResourceByResId {
+ method @DrawableRes public int getResourceId();
+ }
+
+ public static final class ResourceBuilders.AndroidImageResourceByResId.Builder {
+ ctor public ResourceBuilders.AndroidImageResourceByResId.Builder();
+ method public androidx.wear.protolayout.ResourceBuilders.AndroidImageResourceByResId build();
+ method public androidx.wear.protolayout.ResourceBuilders.AndroidImageResourceByResId.Builder setResourceId(@DrawableRes int);
+ }
+
+ public static final class ResourceBuilders.ImageResource {
+ method public androidx.wear.protolayout.ResourceBuilders.AndroidImageResourceByResId? getAndroidResourceByResId();
+ method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource? getInlineResource();
+ }
+
+ public static final class ResourceBuilders.ImageResource.Builder {
+ ctor public ResourceBuilders.ImageResource.Builder();
+ method public androidx.wear.protolayout.ResourceBuilders.ImageResource build();
+ method public androidx.wear.protolayout.ResourceBuilders.ImageResource.Builder setAndroidResourceByResId(androidx.wear.protolayout.ResourceBuilders.AndroidImageResourceByResId);
+ method public androidx.wear.protolayout.ResourceBuilders.ImageResource.Builder setInlineResource(androidx.wear.protolayout.ResourceBuilders.InlineImageResource);
+ }
+
+ public static final class ResourceBuilders.InlineImageResource {
+ method public byte[] getData();
+ method public int getFormat();
+ method @Dimension(unit=androidx.annotation.Dimension.PX) public int getHeightPx();
+ method @Dimension(unit=androidx.annotation.Dimension.PX) public int getWidthPx();
+ }
+
+ public static final class ResourceBuilders.InlineImageResource.Builder {
+ ctor public ResourceBuilders.InlineImageResource.Builder();
+ method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource build();
+ method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource.Builder setData(byte[]);
+ method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource.Builder setFormat(int);
+ method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource.Builder setHeightPx(@Dimension(unit=androidx.annotation.Dimension.PX) int);
+ method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource.Builder setWidthPx(@Dimension(unit=androidx.annotation.Dimension.PX) int);
+ }
+
+ public static final class ResourceBuilders.Resources {
+ method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public static androidx.wear.protolayout.ResourceBuilders.Resources? fromByteArray(byte[]);
+ method public java.util.Map<java.lang.String!,androidx.wear.protolayout.ResourceBuilders.ImageResource!> getIdToImageMapping();
+ method public String getVersion();
+ method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public byte[] toByteArray();
+ }
+
+ public static final class ResourceBuilders.Resources.Builder {
+ ctor public ResourceBuilders.Resources.Builder();
+ method public androidx.wear.protolayout.ResourceBuilders.Resources.Builder addIdToImageMapping(String, androidx.wear.protolayout.ResourceBuilders.ImageResource);
+ method public androidx.wear.protolayout.ResourceBuilders.Resources build();
+ method public androidx.wear.protolayout.ResourceBuilders.Resources.Builder setVersion(String);
+ }
+
+ public final class StateBuilders {
+ }
+
+ public static final class StateBuilders.State {
+ method public String getLastClickableId();
+ }
+
+ public static final class StateBuilders.State.Builder {
+ ctor public StateBuilders.State.Builder();
+ method public androidx.wear.protolayout.StateBuilders.State build();
+ }
+
+ public final class TimelineBuilders {
+ }
+
+ public static final class TimelineBuilders.TimeInterval {
+ method public long getEndMillis();
+ method public long getStartMillis();
+ }
+
+ public static final class TimelineBuilders.TimeInterval.Builder {
+ ctor public TimelineBuilders.TimeInterval.Builder();
+ method public androidx.wear.protolayout.TimelineBuilders.TimeInterval build();
+ method public androidx.wear.protolayout.TimelineBuilders.TimeInterval.Builder setEndMillis(long);
+ method public androidx.wear.protolayout.TimelineBuilders.TimeInterval.Builder setStartMillis(long);
+ }
+
+ public static final class TimelineBuilders.Timeline {
+ method public static androidx.wear.protolayout.TimelineBuilders.Timeline fromLayoutElement(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public java.util.List<androidx.wear.protolayout.TimelineBuilders.TimelineEntry!> getTimelineEntries();
+ }
+
+ public static final class TimelineBuilders.Timeline.Builder {
+ ctor public TimelineBuilders.Timeline.Builder();
+ method public androidx.wear.protolayout.TimelineBuilders.Timeline.Builder addTimelineEntry(androidx.wear.protolayout.TimelineBuilders.TimelineEntry);
+ method public androidx.wear.protolayout.TimelineBuilders.Timeline build();
+ }
+
+ public static final class TimelineBuilders.TimelineEntry {
+ method public static androidx.wear.protolayout.TimelineBuilders.TimelineEntry fromLayoutElement(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Layout? getLayout();
+ method public androidx.wear.protolayout.TimelineBuilders.TimeInterval? getValidity();
+ }
+
+ public static final class TimelineBuilders.TimelineEntry.Builder {
+ ctor public TimelineBuilders.TimelineEntry.Builder();
+ method public androidx.wear.protolayout.TimelineBuilders.TimelineEntry build();
+ method public androidx.wear.protolayout.TimelineBuilders.TimelineEntry.Builder setLayout(androidx.wear.protolayout.LayoutElementBuilders.Layout);
+ method public androidx.wear.protolayout.TimelineBuilders.TimelineEntry.Builder setValidity(androidx.wear.protolayout.TimelineBuilders.TimeInterval);
+ }
+
+ public final class TypeBuilders {
+ }
+
+ public static final class TypeBuilders.BoolProp {
+ method public boolean getValue();
+ }
+
+ public static final class TypeBuilders.BoolProp.Builder {
+ ctor public TypeBuilders.BoolProp.Builder();
+ method public androidx.wear.protolayout.TypeBuilders.BoolProp build();
+ method public androidx.wear.protolayout.TypeBuilders.BoolProp.Builder setValue(boolean);
+ }
+
+ public static final class TypeBuilders.FloatProp {
+ method public float getValue();
+ }
+
+ public static final class TypeBuilders.FloatProp.Builder {
+ ctor public TypeBuilders.FloatProp.Builder();
+ method public androidx.wear.protolayout.TypeBuilders.FloatProp build();
+ method public androidx.wear.protolayout.TypeBuilders.FloatProp.Builder setValue(float);
+ }
+
+ public static final class TypeBuilders.Int32Prop {
+ method public int getValue();
+ }
+
+ public static final class TypeBuilders.Int32Prop.Builder {
+ ctor public TypeBuilders.Int32Prop.Builder();
+ method public androidx.wear.protolayout.TypeBuilders.Int32Prop build();
+ method public androidx.wear.protolayout.TypeBuilders.Int32Prop.Builder setValue(int);
+ }
+
+ public static final class TypeBuilders.StringProp {
+ method public String getValue();
+ }
+
+ public static final class TypeBuilders.StringProp.Builder {
+ ctor public TypeBuilders.StringProp.Builder();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp build();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp.Builder setValue(String);
+ }
+
+}
+
diff --git a/wear/protolayout/protolayout/api/restricted_current.txt b/wear/protolayout/protolayout/api/restricted_current.txt
index e6f50d0..080e325 100644
--- a/wear/protolayout/protolayout/api/restricted_current.txt
+++ b/wear/protolayout/protolayout/api/restricted_current.txt
@@ -1 +1,984 @@
// Signature format: 4.0
+package androidx.wear.protolayout {
+
+ public final class ActionBuilders {
+ method public static androidx.wear.protolayout.ActionBuilders.AndroidBooleanExtra booleanExtra(boolean);
+ method public static androidx.wear.protolayout.ActionBuilders.AndroidDoubleExtra doubleExtra(double);
+ method public static androidx.wear.protolayout.ActionBuilders.AndroidIntExtra intExtra(int);
+ method public static androidx.wear.protolayout.ActionBuilders.AndroidLongExtra longExtra(long);
+ method public static androidx.wear.protolayout.ActionBuilders.AndroidStringExtra stringExtra(String);
+ }
+
+ public static interface ActionBuilders.Action {
+ }
+
+ public static interface ActionBuilders.Action.Builder {
+ method public androidx.wear.protolayout.ActionBuilders.Action build();
+ }
+
+ public static final class ActionBuilders.AndroidActivity {
+ method public String getClassName();
+ method public java.util.Map<java.lang.String!,androidx.wear.protolayout.ActionBuilders.AndroidExtra!> getKeyToExtraMapping();
+ method public String getPackageName();
+ }
+
+ public static final class ActionBuilders.AndroidActivity.Builder {
+ ctor public ActionBuilders.AndroidActivity.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidActivity.Builder addKeyToExtraMapping(String, androidx.wear.protolayout.ActionBuilders.AndroidExtra);
+ method public androidx.wear.protolayout.ActionBuilders.AndroidActivity build();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidActivity.Builder setClassName(String);
+ method public androidx.wear.protolayout.ActionBuilders.AndroidActivity.Builder setPackageName(String);
+ }
+
+ public static final class ActionBuilders.AndroidBooleanExtra implements androidx.wear.protolayout.ActionBuilders.AndroidExtra {
+ method public boolean getValue();
+ }
+
+ public static final class ActionBuilders.AndroidBooleanExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ ctor public ActionBuilders.AndroidBooleanExtra.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidBooleanExtra build();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidBooleanExtra.Builder setValue(boolean);
+ }
+
+ public static final class ActionBuilders.AndroidDoubleExtra implements androidx.wear.protolayout.ActionBuilders.AndroidExtra {
+ method public double getValue();
+ }
+
+ public static final class ActionBuilders.AndroidDoubleExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ ctor public ActionBuilders.AndroidDoubleExtra.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidDoubleExtra build();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidDoubleExtra.Builder setValue(double);
+ }
+
+ public static interface ActionBuilders.AndroidExtra {
+ }
+
+ public static interface ActionBuilders.AndroidExtra.Builder {
+ method public androidx.wear.protolayout.ActionBuilders.AndroidExtra build();
+ }
+
+ public static final class ActionBuilders.AndroidIntExtra implements androidx.wear.protolayout.ActionBuilders.AndroidExtra {
+ method public int getValue();
+ }
+
+ public static final class ActionBuilders.AndroidIntExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ ctor public ActionBuilders.AndroidIntExtra.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidIntExtra build();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidIntExtra.Builder setValue(int);
+ }
+
+ public static final class ActionBuilders.AndroidLongExtra implements androidx.wear.protolayout.ActionBuilders.AndroidExtra {
+ method public long getValue();
+ }
+
+ public static final class ActionBuilders.AndroidLongExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ ctor public ActionBuilders.AndroidLongExtra.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidLongExtra build();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidLongExtra.Builder setValue(long);
+ }
+
+ public static final class ActionBuilders.AndroidStringExtra implements androidx.wear.protolayout.ActionBuilders.AndroidExtra {
+ method public String getValue();
+ }
+
+ public static final class ActionBuilders.AndroidStringExtra.Builder implements androidx.wear.protolayout.ActionBuilders.AndroidExtra.Builder {
+ ctor public ActionBuilders.AndroidStringExtra.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidStringExtra build();
+ method public androidx.wear.protolayout.ActionBuilders.AndroidStringExtra.Builder setValue(String);
+ }
+
+ public static final class ActionBuilders.LaunchAction implements androidx.wear.protolayout.ActionBuilders.Action {
+ method public androidx.wear.protolayout.ActionBuilders.AndroidActivity? getAndroidActivity();
+ }
+
+ public static final class ActionBuilders.LaunchAction.Builder implements androidx.wear.protolayout.ActionBuilders.Action.Builder {
+ ctor public ActionBuilders.LaunchAction.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.LaunchAction build();
+ method public androidx.wear.protolayout.ActionBuilders.LaunchAction.Builder setAndroidActivity(androidx.wear.protolayout.ActionBuilders.AndroidActivity);
+ }
+
+ public static final class ActionBuilders.LoadAction implements androidx.wear.protolayout.ActionBuilders.Action {
+ method public androidx.wear.protolayout.StateBuilders.State? getRequestState();
+ }
+
+ public static final class ActionBuilders.LoadAction.Builder implements androidx.wear.protolayout.ActionBuilders.Action.Builder {
+ ctor public ActionBuilders.LoadAction.Builder();
+ method public androidx.wear.protolayout.ActionBuilders.LoadAction build();
+ method public androidx.wear.protolayout.ActionBuilders.LoadAction.Builder setRequestState(androidx.wear.protolayout.StateBuilders.State);
+ }
+
+ public final class ColorBuilders {
+ method public static androidx.wear.protolayout.ColorBuilders.ColorProp argb(@ColorInt int);
+ }
+
+ public static final class ColorBuilders.ColorProp {
+ method @ColorInt public int getArgb();
+ }
+
+ public static final class ColorBuilders.ColorProp.Builder {
+ ctor public ColorBuilders.ColorProp.Builder();
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp build();
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp.Builder setArgb(@ColorInt int);
+ }
+
+ public final class DeviceParametersBuilders {
+ field public static final int DEVICE_PLATFORM_UNDEFINED = 0; // 0x0
+ field public static final int DEVICE_PLATFORM_WEAR_OS = 1; // 0x1
+ field public static final int SCREEN_SHAPE_RECT = 2; // 0x2
+ field public static final int SCREEN_SHAPE_ROUND = 1; // 0x1
+ field public static final int SCREEN_SHAPE_UNDEFINED = 0; // 0x0
+ }
+
+ public static final class DeviceParametersBuilders.DeviceParameters {
+ method public int getDevicePlatform();
+ method @FloatRange(from=0.0, fromInclusive=false, toInclusive=false) public float getScreenDensity();
+ method @Dimension(unit=androidx.annotation.Dimension.DP) public int getScreenHeightDp();
+ method public int getScreenShape();
+ method @Dimension(unit=androidx.annotation.Dimension.DP) public int getScreenWidthDp();
+ }
+
+ public static final class DeviceParametersBuilders.DeviceParameters.Builder {
+ ctor public DeviceParametersBuilders.DeviceParameters.Builder();
+ method public androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters build();
+ method public androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters.Builder setDevicePlatform(int);
+ method public androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters.Builder setScreenDensity(@FloatRange(from=0.0, fromInclusive=false, toInclusive=false) float);
+ method public androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters.Builder setScreenHeightDp(@Dimension(unit=androidx.annotation.Dimension.DP) int);
+ method public androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters.Builder setScreenShape(int);
+ method public androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters.Builder setScreenWidthDp(@Dimension(unit=androidx.annotation.Dimension.DP) int);
+ }
+
+ public final class DimensionBuilders {
+ method public static androidx.wear.protolayout.DimensionBuilders.DegreesProp degrees(float);
+ method public static androidx.wear.protolayout.DimensionBuilders.DpProp dp(@Dimension(unit=androidx.annotation.Dimension.DP) float);
+ method public static androidx.wear.protolayout.DimensionBuilders.EmProp em(int);
+ method public static androidx.wear.protolayout.DimensionBuilders.EmProp em(float);
+ method public static androidx.wear.protolayout.DimensionBuilders.ExpandedDimensionProp expand();
+ method public static androidx.wear.protolayout.DimensionBuilders.SpProp sp(@Dimension(unit=androidx.annotation.Dimension.SP) float);
+ method public static androidx.wear.protolayout.DimensionBuilders.WrappedDimensionProp wrap();
+ }
+
+ public static interface DimensionBuilders.ContainerDimension {
+ }
+
+ public static interface DimensionBuilders.ContainerDimension.Builder {
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension build();
+ }
+
+ public static final class DimensionBuilders.DegreesProp {
+ method public float getValue();
+ }
+
+ public static final class DimensionBuilders.DegreesProp.Builder {
+ ctor public DimensionBuilders.DegreesProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.DegreesProp build();
+ method public androidx.wear.protolayout.DimensionBuilders.DegreesProp.Builder setValue(float);
+ }
+
+ public static final class DimensionBuilders.DpProp implements androidx.wear.protolayout.DimensionBuilders.ContainerDimension androidx.wear.protolayout.DimensionBuilders.ImageDimension androidx.wear.protolayout.DimensionBuilders.SpacerDimension {
+ method @Dimension(unit=androidx.annotation.Dimension.DP) public float getValue();
+ }
+
+ public static final class DimensionBuilders.DpProp.Builder implements androidx.wear.protolayout.DimensionBuilders.ContainerDimension.Builder androidx.wear.protolayout.DimensionBuilders.ImageDimension.Builder androidx.wear.protolayout.DimensionBuilders.SpacerDimension.Builder {
+ ctor public DimensionBuilders.DpProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp build();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp.Builder setValue(@Dimension(unit=androidx.annotation.Dimension.DP) float);
+ }
+
+ public static final class DimensionBuilders.EmProp {
+ method public float getValue();
+ }
+
+ public static final class DimensionBuilders.EmProp.Builder {
+ ctor public DimensionBuilders.EmProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.EmProp build();
+ method public androidx.wear.protolayout.DimensionBuilders.EmProp.Builder setValue(float);
+ }
+
+ public static final class DimensionBuilders.ExpandedDimensionProp implements androidx.wear.protolayout.DimensionBuilders.ContainerDimension androidx.wear.protolayout.DimensionBuilders.ImageDimension {
+ }
+
+ public static final class DimensionBuilders.ExpandedDimensionProp.Builder implements androidx.wear.protolayout.DimensionBuilders.ContainerDimension.Builder androidx.wear.protolayout.DimensionBuilders.ImageDimension.Builder {
+ ctor public DimensionBuilders.ExpandedDimensionProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.ExpandedDimensionProp build();
+ }
+
+ public static interface DimensionBuilders.ImageDimension {
+ }
+
+ public static interface DimensionBuilders.ImageDimension.Builder {
+ method public androidx.wear.protolayout.DimensionBuilders.ImageDimension build();
+ }
+
+ public static final class DimensionBuilders.ProportionalDimensionProp implements androidx.wear.protolayout.DimensionBuilders.ImageDimension {
+ method @IntRange(from=0) public int getAspectRatioHeight();
+ method @IntRange(from=0) public int getAspectRatioWidth();
+ }
+
+ public static final class DimensionBuilders.ProportionalDimensionProp.Builder implements androidx.wear.protolayout.DimensionBuilders.ImageDimension.Builder {
+ ctor public DimensionBuilders.ProportionalDimensionProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.ProportionalDimensionProp build();
+ method public androidx.wear.protolayout.DimensionBuilders.ProportionalDimensionProp.Builder setAspectRatioHeight(@IntRange(from=0) int);
+ method public androidx.wear.protolayout.DimensionBuilders.ProportionalDimensionProp.Builder setAspectRatioWidth(@IntRange(from=0) int);
+ }
+
+ public static final class DimensionBuilders.SpProp {
+ method @Dimension(unit=androidx.annotation.Dimension.SP) public float getValue();
+ }
+
+ public static final class DimensionBuilders.SpProp.Builder {
+ ctor public DimensionBuilders.SpProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.SpProp build();
+ method public androidx.wear.protolayout.DimensionBuilders.SpProp.Builder setValue(@Dimension(unit=androidx.annotation.Dimension.SP) float);
+ }
+
+ public static interface DimensionBuilders.SpacerDimension {
+ }
+
+ public static interface DimensionBuilders.SpacerDimension.Builder {
+ method public androidx.wear.protolayout.DimensionBuilders.SpacerDimension build();
+ }
+
+ public static final class DimensionBuilders.WrappedDimensionProp implements androidx.wear.protolayout.DimensionBuilders.ContainerDimension {
+ }
+
+ public static final class DimensionBuilders.WrappedDimensionProp.Builder implements androidx.wear.protolayout.DimensionBuilders.ContainerDimension.Builder {
+ ctor public DimensionBuilders.WrappedDimensionProp.Builder();
+ method public androidx.wear.protolayout.DimensionBuilders.WrappedDimensionProp build();
+ }
+
+ public final class LayoutElementBuilders {
+ field public static final int ARC_ANCHOR_CENTER = 2; // 0x2
+ field public static final int ARC_ANCHOR_END = 3; // 0x3
+ field public static final int ARC_ANCHOR_START = 1; // 0x1
+ field public static final int ARC_ANCHOR_UNDEFINED = 0; // 0x0
+ field public static final int CONTENT_SCALE_MODE_CROP = 2; // 0x2
+ field public static final int CONTENT_SCALE_MODE_FILL_BOUNDS = 3; // 0x3
+ field public static final int CONTENT_SCALE_MODE_FIT = 1; // 0x1
+ field public static final int CONTENT_SCALE_MODE_UNDEFINED = 0; // 0x0
+ field public static final int FONT_VARIANT_BODY = 2; // 0x2
+ field public static final int FONT_VARIANT_TITLE = 1; // 0x1
+ field public static final int FONT_VARIANT_UNDEFINED = 0; // 0x0
+ field public static final int FONT_WEIGHT_BOLD = 700; // 0x2bc
+ field public static final int FONT_WEIGHT_NORMAL = 400; // 0x190
+ field public static final int FONT_WEIGHT_UNDEFINED = 0; // 0x0
+ field public static final int HORIZONTAL_ALIGN_CENTER = 2; // 0x2
+ field public static final int HORIZONTAL_ALIGN_END = 5; // 0x5
+ field public static final int HORIZONTAL_ALIGN_LEFT = 1; // 0x1
+ field public static final int HORIZONTAL_ALIGN_RIGHT = 3; // 0x3
+ field public static final int HORIZONTAL_ALIGN_START = 4; // 0x4
+ field public static final int HORIZONTAL_ALIGN_UNDEFINED = 0; // 0x0
+ field public static final int SPAN_VERTICAL_ALIGN_BOTTOM = 1; // 0x1
+ field public static final int SPAN_VERTICAL_ALIGN_TEXT_BASELINE = 2; // 0x2
+ field public static final int SPAN_VERTICAL_ALIGN_UNDEFINED = 0; // 0x0
+ field public static final int TEXT_ALIGN_CENTER = 2; // 0x2
+ field public static final int TEXT_ALIGN_END = 3; // 0x3
+ field public static final int TEXT_ALIGN_START = 1; // 0x1
+ field public static final int TEXT_ALIGN_UNDEFINED = 0; // 0x0
+ field public static final int TEXT_OVERFLOW_ELLIPSIZE_END = 2; // 0x2
+ field public static final int TEXT_OVERFLOW_TRUNCATE = 1; // 0x1
+ field public static final int TEXT_OVERFLOW_UNDEFINED = 0; // 0x0
+ field public static final int VERTICAL_ALIGN_BOTTOM = 3; // 0x3
+ field public static final int VERTICAL_ALIGN_CENTER = 2; // 0x2
+ field public static final int VERTICAL_ALIGN_TOP = 1; // 0x1
+ field public static final int VERTICAL_ALIGN_UNDEFINED = 0; // 0x0
+ }
+
+ public static final class LayoutElementBuilders.Arc implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public androidx.wear.protolayout.DimensionBuilders.DegreesProp? getAnchorAngle();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAnchorTypeProp? getAnchorType();
+ method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement!> getContents();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp? getVerticalAlign();
+ }
+
+ public static final class LayoutElementBuilders.Arc.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Arc.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder setAnchorAngle(androidx.wear.protolayout.DimensionBuilders.DegreesProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder setAnchorType(androidx.wear.protolayout.LayoutElementBuilders.ArcAnchorTypeProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder setAnchorType(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder setVerticalAlign(androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Arc.Builder setVerticalAlign(int);
+ }
+
+ public static final class LayoutElementBuilders.ArcAdapter implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement {
+ method public androidx.wear.protolayout.LayoutElementBuilders.LayoutElement? getContent();
+ method public androidx.wear.protolayout.TypeBuilders.BoolProp? getRotateContents();
+ }
+
+ public static final class LayoutElementBuilders.ArcAdapter.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ ctor public LayoutElementBuilders.ArcAdapter.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAdapter build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAdapter.Builder setContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAdapter.Builder setRotateContents(androidx.wear.protolayout.TypeBuilders.BoolProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAdapter.Builder setRotateContents(boolean);
+ }
+
+ public static final class LayoutElementBuilders.ArcAnchorTypeProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.ArcAnchorTypeProp.Builder {
+ ctor public LayoutElementBuilders.ArcAnchorTypeProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAnchorTypeProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcAnchorTypeProp.Builder setValue(int);
+ }
+
+ public static interface LayoutElementBuilders.ArcLayoutElement {
+ }
+
+ public static interface LayoutElementBuilders.ArcLayoutElement.Builder {
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement build();
+ }
+
+ public static final class LayoutElementBuilders.ArcLine implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement {
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp? getColor();
+ method public androidx.wear.protolayout.DimensionBuilders.DegreesProp? getLength();
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers? getModifiers();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getThickness();
+ }
+
+ public static final class LayoutElementBuilders.ArcLine.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ ctor public LayoutElementBuilders.ArcLine.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine.Builder setLength(androidx.wear.protolayout.DimensionBuilders.DegreesProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.ArcModifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcLine.Builder setThickness(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ }
+
+ public static final class LayoutElementBuilders.ArcSpacer implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement {
+ method public androidx.wear.protolayout.DimensionBuilders.DegreesProp? getLength();
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers? getModifiers();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getThickness();
+ }
+
+ public static final class LayoutElementBuilders.ArcSpacer.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ ctor public LayoutElementBuilders.ArcSpacer.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcSpacer build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcSpacer.Builder setLength(androidx.wear.protolayout.DimensionBuilders.DegreesProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcSpacer.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.ArcModifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcSpacer.Builder setThickness(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ }
+
+ public static final class LayoutElementBuilders.ArcText implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement {
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle? getFontStyle();
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers? getModifiers();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp? getText();
+ }
+
+ public static final class LayoutElementBuilders.ArcText.Builder implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement.Builder {
+ ctor public LayoutElementBuilders.ArcText.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcText build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcText.Builder setFontStyle(androidx.wear.protolayout.LayoutElementBuilders.FontStyle);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcText.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.ArcModifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcText.Builder setText(androidx.wear.protolayout.TypeBuilders.StringProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcText.Builder setText(String);
+ }
+
+ public static final class LayoutElementBuilders.Box implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.LayoutElement!> getContents();
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getHeight();
+ method public androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp? getHorizontalAlignment();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp? getVerticalAlignment();
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getWidth();
+ }
+
+ public static final class LayoutElementBuilders.Box.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Box.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setHorizontalAlignment(androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setHorizontalAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setVerticalAlignment(androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setVerticalAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Box.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
+ }
+
+ public static final class LayoutElementBuilders.ColorFilter {
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp? getTint();
+ }
+
+ public static final class LayoutElementBuilders.ColorFilter.Builder {
+ ctor public LayoutElementBuilders.ColorFilter.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ColorFilter build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ColorFilter.Builder setTint(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ }
+
+ public static final class LayoutElementBuilders.Column implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.LayoutElement!> getContents();
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getHeight();
+ method public androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp? getHorizontalAlignment();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getWidth();
+ }
+
+ public static final class LayoutElementBuilders.Column.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Column.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder setHorizontalAlignment(androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder setHorizontalAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Column.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
+ }
+
+ public static final class LayoutElementBuilders.ContentScaleModeProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.ContentScaleModeProp.Builder {
+ ctor public LayoutElementBuilders.ContentScaleModeProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ContentScaleModeProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ContentScaleModeProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.FontStyle {
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp? getColor();
+ method public androidx.wear.protolayout.TypeBuilders.BoolProp? getItalic();
+ method public androidx.wear.protolayout.DimensionBuilders.EmProp? getLetterSpacing();
+ method public androidx.wear.protolayout.DimensionBuilders.SpProp? getSize();
+ method public androidx.wear.protolayout.TypeBuilders.BoolProp? getUnderline();
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontWeightProp? getWeight();
+ }
+
+ public static final class LayoutElementBuilders.FontStyle.Builder {
+ ctor public LayoutElementBuilders.FontStyle.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setItalic(androidx.wear.protolayout.TypeBuilders.BoolProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setItalic(boolean);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setLetterSpacing(androidx.wear.protolayout.DimensionBuilders.EmProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setSize(androidx.wear.protolayout.DimensionBuilders.SpProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setUnderline(androidx.wear.protolayout.TypeBuilders.BoolProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setUnderline(boolean);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setWeight(androidx.wear.protolayout.LayoutElementBuilders.FontWeightProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setWeight(int);
+ }
+
+ public static class LayoutElementBuilders.FontStyles {
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder body1(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder body2(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder button(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder caption1(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder caption2(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder display1(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder display2(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder display3(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder title1(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder title2(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ method public static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder title3(androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters);
+ }
+
+ public static final class LayoutElementBuilders.FontWeightProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.FontWeightProp.Builder {
+ ctor public LayoutElementBuilders.FontWeightProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontWeightProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontWeightProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.HorizontalAlignmentProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.HorizontalAlignmentProp.Builder {
+ ctor public LayoutElementBuilders.HorizontalAlignmentProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.Image implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public androidx.wear.protolayout.LayoutElementBuilders.ColorFilter? getColorFilter();
+ method public androidx.wear.protolayout.LayoutElementBuilders.ContentScaleModeProp? getContentScaleMode();
+ method public androidx.wear.protolayout.DimensionBuilders.ImageDimension? getHeight();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp? getResourceId();
+ method public androidx.wear.protolayout.DimensionBuilders.ImageDimension? getWidth();
+ }
+
+ public static final class LayoutElementBuilders.Image.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Image.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setColorFilter(androidx.wear.protolayout.LayoutElementBuilders.ColorFilter);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setContentScaleMode(androidx.wear.protolayout.LayoutElementBuilders.ContentScaleModeProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setContentScaleMode(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.ImageDimension);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setResourceId(androidx.wear.protolayout.TypeBuilders.StringProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setResourceId(String);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Image.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.ImageDimension);
+ }
+
+ public static final class LayoutElementBuilders.Layout {
+ method public static androidx.wear.protolayout.LayoutElementBuilders.Layout fromLayoutElement(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.LayoutElement? getRoot();
+ }
+
+ public static final class LayoutElementBuilders.Layout.Builder {
+ ctor public LayoutElementBuilders.Layout.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Layout build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Layout.Builder setRoot(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ }
+
+ public static interface LayoutElementBuilders.LayoutElement {
+ }
+
+ public static interface LayoutElementBuilders.LayoutElement.Builder {
+ method public androidx.wear.protolayout.LayoutElementBuilders.LayoutElement build();
+ }
+
+ public static final class LayoutElementBuilders.Row implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.LayoutElement!> getContents();
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getHeight();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp? getVerticalAlignment();
+ method public androidx.wear.protolayout.DimensionBuilders.ContainerDimension? getWidth();
+ }
+
+ public static final class LayoutElementBuilders.Row.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Row.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder addContent(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder setVerticalAlignment(androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder setVerticalAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Row.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.ContainerDimension);
+ }
+
+ public static final class LayoutElementBuilders.Spacer implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public androidx.wear.protolayout.DimensionBuilders.SpacerDimension? getHeight();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.DimensionBuilders.SpacerDimension? getWidth();
+ }
+
+ public static final class LayoutElementBuilders.Spacer.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Spacer.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spacer build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spacer.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.SpacerDimension);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spacer.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spacer.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.SpacerDimension);
+ }
+
+ public static interface LayoutElementBuilders.Span {
+ }
+
+ public static interface LayoutElementBuilders.Span.Builder {
+ method public androidx.wear.protolayout.LayoutElementBuilders.Span build();
+ }
+
+ public static final class LayoutElementBuilders.SpanImage implements androidx.wear.protolayout.LayoutElementBuilders.Span {
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanVerticalAlignmentProp? getAlignment();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getHeight();
+ method public androidx.wear.protolayout.ModifiersBuilders.SpanModifiers? getModifiers();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp? getResourceId();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getWidth();
+ }
+
+ public static final class LayoutElementBuilders.SpanImage.Builder implements androidx.wear.protolayout.LayoutElementBuilders.Span.Builder {
+ ctor public LayoutElementBuilders.SpanImage.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setAlignment(androidx.wear.protolayout.LayoutElementBuilders.SpanVerticalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setHeight(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.SpanModifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setResourceId(androidx.wear.protolayout.TypeBuilders.StringProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setResourceId(String);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanImage.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ }
+
+ public static final class LayoutElementBuilders.SpanText implements androidx.wear.protolayout.LayoutElementBuilders.Span {
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle? getFontStyle();
+ method public androidx.wear.protolayout.ModifiersBuilders.SpanModifiers? getModifiers();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp? getText();
+ }
+
+ public static final class LayoutElementBuilders.SpanText.Builder implements androidx.wear.protolayout.LayoutElementBuilders.Span.Builder {
+ ctor public LayoutElementBuilders.SpanText.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanText build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanText.Builder setFontStyle(androidx.wear.protolayout.LayoutElementBuilders.FontStyle);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanText.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.SpanModifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanText.Builder setText(androidx.wear.protolayout.TypeBuilders.StringProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanText.Builder setText(String);
+ }
+
+ public static final class LayoutElementBuilders.SpanVerticalAlignmentProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.SpanVerticalAlignmentProp.Builder {
+ ctor public LayoutElementBuilders.SpanVerticalAlignmentProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanVerticalAlignmentProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.SpanVerticalAlignmentProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.Spannable implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public androidx.wear.protolayout.DimensionBuilders.SpProp? getLineHeight();
+ method public androidx.wear.protolayout.TypeBuilders.Int32Prop? getMaxLines();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp? getMultilineAlignment();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextOverflowProp? getOverflow();
+ method public java.util.List<androidx.wear.protolayout.LayoutElementBuilders.Span!> getSpans();
+ }
+
+ public static final class LayoutElementBuilders.Spannable.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Spannable.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder addSpan(androidx.wear.protolayout.LayoutElementBuilders.Span);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setLineHeight(androidx.wear.protolayout.DimensionBuilders.SpProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setMaxLines(androidx.wear.protolayout.TypeBuilders.Int32Prop);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setMaxLines(@IntRange(from=1) int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setMultilineAlignment(androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setMultilineAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setOverflow(androidx.wear.protolayout.LayoutElementBuilders.TextOverflowProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setOverflow(int);
+ }
+
+ public static final class LayoutElementBuilders.Text implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+ method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle? getFontStyle();
+ method public androidx.wear.protolayout.DimensionBuilders.SpProp? getLineHeight();
+ method public androidx.wear.protolayout.TypeBuilders.Int32Prop? getMaxLines();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextAlignmentProp? getMultilineAlignment();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextOverflowProp? getOverflow();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp? getText();
+ }
+
+ public static final class LayoutElementBuilders.Text.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
+ ctor public LayoutElementBuilders.Text.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setFontStyle(androidx.wear.protolayout.LayoutElementBuilders.FontStyle);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setLineHeight(androidx.wear.protolayout.DimensionBuilders.SpProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setMaxLines(androidx.wear.protolayout.TypeBuilders.Int32Prop);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setMaxLines(@IntRange(from=1) int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setMultilineAlignment(androidx.wear.protolayout.LayoutElementBuilders.TextAlignmentProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setMultilineAlignment(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setOverflow(androidx.wear.protolayout.LayoutElementBuilders.TextOverflowProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setOverflow(int);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setText(androidx.wear.protolayout.TypeBuilders.StringProp);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setText(String);
+ }
+
+ public static final class LayoutElementBuilders.TextAlignmentProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.TextAlignmentProp.Builder {
+ ctor public LayoutElementBuilders.TextAlignmentProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextAlignmentProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextAlignmentProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.TextOverflowProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.TextOverflowProp.Builder {
+ ctor public LayoutElementBuilders.TextOverflowProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextOverflowProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.TextOverflowProp.Builder setValue(int);
+ }
+
+ public static final class LayoutElementBuilders.VerticalAlignmentProp {
+ method public int getValue();
+ }
+
+ public static final class LayoutElementBuilders.VerticalAlignmentProp.Builder {
+ ctor public LayoutElementBuilders.VerticalAlignmentProp.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp build();
+ method public androidx.wear.protolayout.LayoutElementBuilders.VerticalAlignmentProp.Builder setValue(int);
+ }
+
+ public final class ModifiersBuilders {
+ }
+
+ public static final class ModifiersBuilders.ArcModifiers {
+ method public androidx.wear.protolayout.ModifiersBuilders.Clickable? getClickable();
+ method public androidx.wear.protolayout.ModifiersBuilders.Semantics? getSemantics();
+ }
+
+ public static final class ModifiersBuilders.ArcModifiers.Builder {
+ ctor public ModifiersBuilders.ArcModifiers.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers build();
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers.Builder setClickable(androidx.wear.protolayout.ModifiersBuilders.Clickable);
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers.Builder setSemantics(androidx.wear.protolayout.ModifiersBuilders.Semantics);
+ }
+
+ public static final class ModifiersBuilders.Background {
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp? getColor();
+ method public androidx.wear.protolayout.ModifiersBuilders.Corner? getCorner();
+ }
+
+ public static final class ModifiersBuilders.Background.Builder {
+ ctor public ModifiersBuilders.Background.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Background build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Background.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Background.Builder setCorner(androidx.wear.protolayout.ModifiersBuilders.Corner);
+ }
+
+ public static final class ModifiersBuilders.Border {
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp? getColor();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getWidth();
+ }
+
+ public static final class ModifiersBuilders.Border.Builder {
+ ctor public ModifiersBuilders.Border.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Border build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Border.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Border.Builder setWidth(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ }
+
+ public static final class ModifiersBuilders.Clickable {
+ method public String getId();
+ method public androidx.wear.protolayout.ActionBuilders.Action? getOnClick();
+ }
+
+ public static final class ModifiersBuilders.Clickable.Builder {
+ ctor public ModifiersBuilders.Clickable.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Clickable build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Clickable.Builder setId(String);
+ method public androidx.wear.protolayout.ModifiersBuilders.Clickable.Builder setOnClick(androidx.wear.protolayout.ActionBuilders.Action);
+ }
+
+ public static final class ModifiersBuilders.Corner {
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getRadius();
+ }
+
+ public static final class ModifiersBuilders.Corner.Builder {
+ ctor public ModifiersBuilders.Corner.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Corner build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Corner.Builder setRadius(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ }
+
+ public static final class ModifiersBuilders.ElementMetadata {
+ method public byte[] getTagData();
+ }
+
+ public static final class ModifiersBuilders.ElementMetadata.Builder {
+ ctor public ModifiersBuilders.ElementMetadata.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.ElementMetadata build();
+ method public androidx.wear.protolayout.ModifiersBuilders.ElementMetadata.Builder setTagData(byte[]);
+ }
+
+ public static final class ModifiersBuilders.Modifiers {
+ method public androidx.wear.protolayout.ModifiersBuilders.Background? getBackground();
+ method public androidx.wear.protolayout.ModifiersBuilders.Border? getBorder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Clickable? getClickable();
+ method public androidx.wear.protolayout.ModifiersBuilders.ElementMetadata? getMetadata();
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding? getPadding();
+ method public androidx.wear.protolayout.ModifiersBuilders.Semantics? getSemantics();
+ }
+
+ public static final class ModifiersBuilders.Modifiers.Builder {
+ ctor public ModifiersBuilders.Modifiers.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setBackground(androidx.wear.protolayout.ModifiersBuilders.Background);
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setBorder(androidx.wear.protolayout.ModifiersBuilders.Border);
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setClickable(androidx.wear.protolayout.ModifiersBuilders.Clickable);
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setMetadata(androidx.wear.protolayout.ModifiersBuilders.ElementMetadata);
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setPadding(androidx.wear.protolayout.ModifiersBuilders.Padding);
+ method public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setSemantics(androidx.wear.protolayout.ModifiersBuilders.Semantics);
+ }
+
+ public static final class ModifiersBuilders.Padding {
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getBottom();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getEnd();
+ method public androidx.wear.protolayout.TypeBuilders.BoolProp? getRtlAware();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getStart();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getTop();
+ }
+
+ public static final class ModifiersBuilders.Padding.Builder {
+ ctor public ModifiersBuilders.Padding.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setAll(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setBottom(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setEnd(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setRtlAware(androidx.wear.protolayout.TypeBuilders.BoolProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setRtlAware(boolean);
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setStart(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ method public androidx.wear.protolayout.ModifiersBuilders.Padding.Builder setTop(androidx.wear.protolayout.DimensionBuilders.DpProp);
+ }
+
+ public static final class ModifiersBuilders.Semantics {
+ method public String getContentDescription();
+ }
+
+ public static final class ModifiersBuilders.Semantics.Builder {
+ ctor public ModifiersBuilders.Semantics.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.Semantics build();
+ method public androidx.wear.protolayout.ModifiersBuilders.Semantics.Builder setContentDescription(String);
+ }
+
+ public static final class ModifiersBuilders.SpanModifiers {
+ method public androidx.wear.protolayout.ModifiersBuilders.Clickable? getClickable();
+ }
+
+ public static final class ModifiersBuilders.SpanModifiers.Builder {
+ ctor public ModifiersBuilders.SpanModifiers.Builder();
+ method public androidx.wear.protolayout.ModifiersBuilders.SpanModifiers build();
+ method public androidx.wear.protolayout.ModifiersBuilders.SpanModifiers.Builder setClickable(androidx.wear.protolayout.ModifiersBuilders.Clickable);
+ }
+
+ public final class ResourceBuilders {
+ field public static final int IMAGE_FORMAT_RGB_565 = 1; // 0x1
+ field public static final int IMAGE_FORMAT_UNDEFINED = 0; // 0x0
+ }
+
+ public static final class ResourceBuilders.AndroidImageResourceByResId {
+ method @DrawableRes public int getResourceId();
+ }
+
+ public static final class ResourceBuilders.AndroidImageResourceByResId.Builder {
+ ctor public ResourceBuilders.AndroidImageResourceByResId.Builder();
+ method public androidx.wear.protolayout.ResourceBuilders.AndroidImageResourceByResId build();
+ method public androidx.wear.protolayout.ResourceBuilders.AndroidImageResourceByResId.Builder setResourceId(@DrawableRes int);
+ }
+
+ public static final class ResourceBuilders.ImageResource {
+ method public androidx.wear.protolayout.ResourceBuilders.AndroidImageResourceByResId? getAndroidResourceByResId();
+ method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource? getInlineResource();
+ }
+
+ public static final class ResourceBuilders.ImageResource.Builder {
+ ctor public ResourceBuilders.ImageResource.Builder();
+ method public androidx.wear.protolayout.ResourceBuilders.ImageResource build();
+ method public androidx.wear.protolayout.ResourceBuilders.ImageResource.Builder setAndroidResourceByResId(androidx.wear.protolayout.ResourceBuilders.AndroidImageResourceByResId);
+ method public androidx.wear.protolayout.ResourceBuilders.ImageResource.Builder setInlineResource(androidx.wear.protolayout.ResourceBuilders.InlineImageResource);
+ }
+
+ public static final class ResourceBuilders.InlineImageResource {
+ method public byte[] getData();
+ method public int getFormat();
+ method @Dimension(unit=androidx.annotation.Dimension.PX) public int getHeightPx();
+ method @Dimension(unit=androidx.annotation.Dimension.PX) public int getWidthPx();
+ }
+
+ public static final class ResourceBuilders.InlineImageResource.Builder {
+ ctor public ResourceBuilders.InlineImageResource.Builder();
+ method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource build();
+ method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource.Builder setData(byte[]);
+ method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource.Builder setFormat(int);
+ method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource.Builder setHeightPx(@Dimension(unit=androidx.annotation.Dimension.PX) int);
+ method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource.Builder setWidthPx(@Dimension(unit=androidx.annotation.Dimension.PX) int);
+ }
+
+ public static final class ResourceBuilders.Resources {
+ method public java.util.Map<java.lang.String!,androidx.wear.protolayout.ResourceBuilders.ImageResource!> getIdToImageMapping();
+ method public String getVersion();
+ }
+
+ public static final class ResourceBuilders.Resources.Builder {
+ ctor public ResourceBuilders.Resources.Builder();
+ method public androidx.wear.protolayout.ResourceBuilders.Resources.Builder addIdToImageMapping(String, androidx.wear.protolayout.ResourceBuilders.ImageResource);
+ method public androidx.wear.protolayout.ResourceBuilders.Resources build();
+ method public androidx.wear.protolayout.ResourceBuilders.Resources.Builder setVersion(String);
+ }
+
+ public final class StateBuilders {
+ }
+
+ public static final class StateBuilders.State {
+ method public String getLastClickableId();
+ }
+
+ public static final class StateBuilders.State.Builder {
+ ctor public StateBuilders.State.Builder();
+ method public androidx.wear.protolayout.StateBuilders.State build();
+ }
+
+ public final class TimelineBuilders {
+ }
+
+ public static final class TimelineBuilders.TimeInterval {
+ method public long getEndMillis();
+ method public long getStartMillis();
+ }
+
+ public static final class TimelineBuilders.TimeInterval.Builder {
+ ctor public TimelineBuilders.TimeInterval.Builder();
+ method public androidx.wear.protolayout.TimelineBuilders.TimeInterval build();
+ method public androidx.wear.protolayout.TimelineBuilders.TimeInterval.Builder setEndMillis(long);
+ method public androidx.wear.protolayout.TimelineBuilders.TimeInterval.Builder setStartMillis(long);
+ }
+
+ public static final class TimelineBuilders.Timeline {
+ method public static androidx.wear.protolayout.TimelineBuilders.Timeline fromLayoutElement(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public java.util.List<androidx.wear.protolayout.TimelineBuilders.TimelineEntry!> getTimelineEntries();
+ }
+
+ public static final class TimelineBuilders.Timeline.Builder {
+ ctor public TimelineBuilders.Timeline.Builder();
+ method public androidx.wear.protolayout.TimelineBuilders.Timeline.Builder addTimelineEntry(androidx.wear.protolayout.TimelineBuilders.TimelineEntry);
+ method public androidx.wear.protolayout.TimelineBuilders.Timeline build();
+ }
+
+ public static final class TimelineBuilders.TimelineEntry {
+ method public static androidx.wear.protolayout.TimelineBuilders.TimelineEntry fromLayoutElement(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
+ method public androidx.wear.protolayout.LayoutElementBuilders.Layout? getLayout();
+ method public androidx.wear.protolayout.TimelineBuilders.TimeInterval? getValidity();
+ }
+
+ public static final class TimelineBuilders.TimelineEntry.Builder {
+ ctor public TimelineBuilders.TimelineEntry.Builder();
+ method public androidx.wear.protolayout.TimelineBuilders.TimelineEntry build();
+ method public androidx.wear.protolayout.TimelineBuilders.TimelineEntry.Builder setLayout(androidx.wear.protolayout.LayoutElementBuilders.Layout);
+ method public androidx.wear.protolayout.TimelineBuilders.TimelineEntry.Builder setValidity(androidx.wear.protolayout.TimelineBuilders.TimeInterval);
+ }
+
+ public final class TypeBuilders {
+ }
+
+ public static final class TypeBuilders.BoolProp {
+ method public boolean getValue();
+ }
+
+ public static final class TypeBuilders.BoolProp.Builder {
+ ctor public TypeBuilders.BoolProp.Builder();
+ method public androidx.wear.protolayout.TypeBuilders.BoolProp build();
+ method public androidx.wear.protolayout.TypeBuilders.BoolProp.Builder setValue(boolean);
+ }
+
+ public static final class TypeBuilders.FloatProp {
+ method public float getValue();
+ }
+
+ public static final class TypeBuilders.FloatProp.Builder {
+ ctor public TypeBuilders.FloatProp.Builder();
+ method public androidx.wear.protolayout.TypeBuilders.FloatProp build();
+ method public androidx.wear.protolayout.TypeBuilders.FloatProp.Builder setValue(float);
+ }
+
+ public static final class TypeBuilders.Int32Prop {
+ method public int getValue();
+ }
+
+ public static final class TypeBuilders.Int32Prop.Builder {
+ ctor public TypeBuilders.Int32Prop.Builder();
+ method public androidx.wear.protolayout.TypeBuilders.Int32Prop build();
+ method public androidx.wear.protolayout.TypeBuilders.Int32Prop.Builder setValue(int);
+ }
+
+ public static final class TypeBuilders.StringProp {
+ method public String getValue();
+ }
+
+ public static final class TypeBuilders.StringProp.Builder {
+ ctor public TypeBuilders.StringProp.Builder();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp build();
+ method public androidx.wear.protolayout.TypeBuilders.StringProp.Builder setValue(String);
+ }
+
+}
+
diff --git a/wear/protolayout/protolayout/build.gradle b/wear/protolayout/protolayout/build.gradle
index 8332043..44f4597 100644
--- a/wear/protolayout/protolayout/build.gradle
+++ b/wear/protolayout/protolayout/build.gradle
@@ -23,10 +23,24 @@
dependencies {
annotationProcessor(libs.nullaway)
+ api("androidx.annotation:annotation:1.2.0")
+
+ implementation("androidx.annotation:annotation-experimental:1.2.0")
+ implementation(project(":wear:protolayout:protolayout-proto"))
+ implementation(project(":wear:protolayout:protolayout-expression"))
+
+ compileOnly(libs.kotlinStdlib) // For annotation-experimental
}
android {
namespace "androidx.wear.protolayout"
+
+ defaultConfig {
+ minSdkVersion 25
+ }
+ buildTypes.all {
+ consumerProguardFiles "proguard-rules.pro"
+ }
}
androidx {
diff --git a/wear/protolayout/protolayout/proguard-rules.pro b/wear/protolayout/protolayout/proguard-rules.pro
new file mode 100644
index 0000000..014faf2
--- /dev/null
+++ b/wear/protolayout/protolayout/proguard-rules.pro
@@ -0,0 +1,20 @@
+# Copyright (C) 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.
+
+# libproto uses reflection to deserialize a Proto, which Proguard can't accurately detect.
+# Keep all the class members of any generated messages to ensure we can deserialize properly inside
+# these classes.
+-keepclassmembers class * extends androidx.wear.protolayout.protobuf.GeneratedMessageLite {
+ <fields>;
+}
\ No newline at end of file
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ActionBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ActionBuilders.java
new file mode 100644
index 0000000..55e8cfe
--- /dev/null
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ActionBuilders.java
@@ -0,0 +1,747 @@
+/*
+ * Copyright 2021-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.
+ */
+
+package androidx.wear.protolayout;
+
+import static androidx.wear.protolayout.expression.Preconditions.checkNotNull;
+
+import android.annotation.SuppressLint;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
+import androidx.wear.protolayout.proto.ActionProto;
+import androidx.wear.protolayout.StateBuilders.State;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/** Builders for actions that can be performed when a user interacts with layout elements. */
+public final class ActionBuilders {
+ private ActionBuilders() {}
+
+ /** Shortcut for building an {@link AndroidStringExtra}. */
+ @NonNull
+ public static AndroidStringExtra stringExtra(@NonNull String value) {
+ return new AndroidStringExtra.Builder().setValue(value).build();
+ }
+
+ /** Shortcut for building an {@link AndroidIntExtra}. */
+ @NonNull
+ public static AndroidIntExtra intExtra(int value) {
+ return new AndroidIntExtra.Builder().setValue(value).build();
+ }
+
+ /** Shortcut for building an {@link AndroidLongExtra}. */
+ @NonNull
+ public static AndroidLongExtra longExtra(long value) {
+ return new AndroidLongExtra.Builder().setValue(value).build();
+ }
+
+ /** Shortcut for building an {@link AndroidDoubleExtra}. */
+ @NonNull
+ public static AndroidDoubleExtra doubleExtra(double value) {
+ return new AndroidDoubleExtra.Builder().setValue(value).build();
+ }
+
+ /** Shortcut for building an {@link AndroidBooleanExtra}. */
+ @NonNull
+ public static AndroidBooleanExtra booleanExtra(boolean value) {
+ return new AndroidBooleanExtra.Builder().setValue(value).build();
+ }
+
+ /** A string value that can be added to an Android intent's extras. */
+ public static final class AndroidStringExtra implements AndroidExtra {
+ private final ActionProto.AndroidStringExtra mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ AndroidStringExtra(
+ ActionProto.AndroidStringExtra impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value. Intended for testing purposes only. */
+ @NonNull
+ public String getValue() {
+ return mImpl.getValue();
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static AndroidStringExtra fromProto(@NonNull ActionProto.AndroidStringExtra proto) {
+ return new AndroidStringExtra(proto, null);
+ }
+
+ @NonNull
+ ActionProto.AndroidStringExtra toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public ActionProto.AndroidExtra toAndroidExtraProto() {
+ return ActionProto.AndroidExtra.newBuilder().setStringVal(mImpl).build();
+ }
+
+ /** Builder for {@link AndroidStringExtra}. */
+ public static final class Builder implements AndroidExtra.Builder {
+ private final ActionProto.AndroidStringExtra.Builder mImpl =
+ ActionProto.AndroidStringExtra.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1281351679);
+
+ public Builder() {}
+
+ /** Sets the value. */
+ @NonNull
+ public Builder setValue(@NonNull String value) {
+ mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, value.hashCode());
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public AndroidStringExtra build() {
+ return new AndroidStringExtra(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** An integer value that can be added to an Android intent's extras. */
+ public static final class AndroidIntExtra implements AndroidExtra {
+ private final ActionProto.AndroidIntExtra mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ AndroidIntExtra(ActionProto.AndroidIntExtra impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value. Intended for testing purposes only. */
+ public int getValue() {
+ return mImpl.getValue();
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static AndroidIntExtra fromProto(@NonNull ActionProto.AndroidIntExtra proto) {
+ return new AndroidIntExtra(proto, null);
+ }
+
+ @NonNull
+ ActionProto.AndroidIntExtra toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public ActionProto.AndroidExtra toAndroidExtraProto() {
+ return ActionProto.AndroidExtra.newBuilder().setIntVal(mImpl).build();
+ }
+
+ /** Builder for {@link AndroidIntExtra}. */
+ public static final class Builder implements AndroidExtra.Builder {
+ private final ActionProto.AndroidIntExtra.Builder mImpl =
+ ActionProto.AndroidIntExtra.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1929293734);
+
+ public Builder() {}
+
+ /** Sets the value. */
+ @NonNull
+ public Builder setValue(int value) {
+ mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, value);
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public AndroidIntExtra build() {
+ return new AndroidIntExtra(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A long value that can be added to an Android intent's extras. */
+ public static final class AndroidLongExtra implements AndroidExtra {
+ private final ActionProto.AndroidLongExtra mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ AndroidLongExtra(ActionProto.AndroidLongExtra impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value. Intended for testing purposes only. */
+ public long getValue() {
+ return mImpl.getValue();
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static AndroidLongExtra fromProto(@NonNull ActionProto.AndroidLongExtra proto) {
+ return new AndroidLongExtra(proto, null);
+ }
+
+ @NonNull
+ ActionProto.AndroidLongExtra toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public ActionProto.AndroidExtra toAndroidExtraProto() {
+ return ActionProto.AndroidExtra.newBuilder().setLongVal(mImpl).build();
+ }
+
+ /** Builder for {@link AndroidLongExtra}. */
+ public static final class Builder implements AndroidExtra.Builder {
+ private final ActionProto.AndroidLongExtra.Builder mImpl =
+ ActionProto.AndroidLongExtra.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-874743180);
+
+ public Builder() {}
+
+ /** Sets the value. */
+ @NonNull
+ public Builder setValue(long value) {
+ mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, Long.hashCode(value));
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public AndroidLongExtra build() {
+ return new AndroidLongExtra(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A double value that can be added to an Android intent's extras. */
+ public static final class AndroidDoubleExtra implements AndroidExtra {
+ private final ActionProto.AndroidDoubleExtra mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ AndroidDoubleExtra(
+ ActionProto.AndroidDoubleExtra impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value. Intended for testing purposes only. */
+ public double getValue() {
+ return mImpl.getValue();
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static AndroidDoubleExtra fromProto(@NonNull ActionProto.AndroidDoubleExtra proto) {
+ return new AndroidDoubleExtra(proto, null);
+ }
+
+ @NonNull
+ ActionProto.AndroidDoubleExtra toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public ActionProto.AndroidExtra toAndroidExtraProto() {
+ return ActionProto.AndroidExtra.newBuilder().setDoubleVal(mImpl).build();
+ }
+
+ /** Builder for {@link AndroidDoubleExtra}. */
+ public static final class Builder implements AndroidExtra.Builder {
+ private final ActionProto.AndroidDoubleExtra.Builder mImpl =
+ ActionProto.AndroidDoubleExtra.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-278689892);
+
+ public Builder() {}
+
+ /** Sets the value. */
+ @NonNull
+ public Builder setValue(double value) {
+ mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, Double.hashCode(value));
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public AndroidDoubleExtra build() {
+ return new AndroidDoubleExtra(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A boolean value that can be added to an Android intent's extras. */
+ public static final class AndroidBooleanExtra implements AndroidExtra {
+ private final ActionProto.AndroidBooleanExtra mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ AndroidBooleanExtra(
+ ActionProto.AndroidBooleanExtra impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value. Intended for testing purposes only. */
+ public boolean getValue() {
+ return mImpl.getValue();
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static AndroidBooleanExtra fromProto(@NonNull ActionProto.AndroidBooleanExtra proto) {
+ return new AndroidBooleanExtra(proto, null);
+ }
+
+ @NonNull
+ ActionProto.AndroidBooleanExtra toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public ActionProto.AndroidExtra toAndroidExtraProto() {
+ return ActionProto.AndroidExtra.newBuilder().setBooleanVal(mImpl).build();
+ }
+
+ /** Builder for {@link AndroidBooleanExtra}. */
+ public static final class Builder implements AndroidExtra.Builder {
+ private final ActionProto.AndroidBooleanExtra.Builder mImpl =
+ ActionProto.AndroidBooleanExtra.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1238672683);
+
+ public Builder() {}
+
+ /** Sets the value. */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @NonNull
+ public Builder setValue(boolean value) {
+ mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, Boolean.hashCode(value));
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public AndroidBooleanExtra build() {
+ return new AndroidBooleanExtra(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /**
+ * Interface defining an item that can be included in the extras of an intent that will be sent to
+ * an Android activity. Supports types in android.os.PersistableBundle, excluding arrays.
+ */
+ public interface AndroidExtra {
+ /**
+ * Get the protocol buffer representation of this object.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ ActionProto.AndroidExtra toAndroidExtraProto();
+
+ /**
+ * Get the fingerprint for this object or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ Fingerprint getFingerprint();
+
+ /** Builder to create {@link AndroidExtra} objects. */
+ @SuppressLint("StaticFinalBuilder")
+ interface Builder {
+
+ /** Builds an instance with values accumulated in this Builder. */
+ @NonNull
+ AndroidExtra build();
+ }
+ }
+
+ @NonNull
+ static AndroidExtra androidExtraFromProto(@NonNull ActionProto.AndroidExtra proto) {
+ if (proto.hasStringVal()) {
+ return AndroidStringExtra.fromProto(proto.getStringVal());
+ }
+ if (proto.hasIntVal()) {
+ return AndroidIntExtra.fromProto(proto.getIntVal());
+ }
+ if (proto.hasLongVal()) {
+ return AndroidLongExtra.fromProto(proto.getLongVal());
+ }
+ if (proto.hasDoubleVal()) {
+ return AndroidDoubleExtra.fromProto(proto.getDoubleVal());
+ }
+ if (proto.hasBooleanVal()) {
+ return AndroidBooleanExtra.fromProto(proto.getBooleanVal());
+ }
+ throw new IllegalStateException("Proto was not a recognised instance of AndroidExtra");
+ }
+
+ /** A launch action to send an intent to an Android activity. */
+ public static final class AndroidActivity {
+ private final ActionProto.AndroidActivity mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ AndroidActivity(ActionProto.AndroidActivity impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets the package name to send the intent to, for example, "com.google.weather". Intended for
+ * testing purposes only.
+ */
+ @NonNull
+ public String getPackageName() {
+ return mImpl.getPackageName();
+ }
+
+ /**
+ * Gets the fully qualified class name (including the package) to send the intent to, for
+ * example, "com.google.weather.WeatherOverviewActivity". Intended for testing purposes only.
+ */
+ @NonNull
+ public String getClassName() {
+ return mImpl.getClassName();
+ }
+
+ /** Gets the extras to be included in the intent. Intended for testing purposes only. */
+ @NonNull
+ public Map<String, AndroidExtra> getKeyToExtraMapping() {
+ Map<String, AndroidExtra> map = new HashMap<>();
+ for (Entry<String, ActionProto.AndroidExtra> entry : mImpl.getKeyToExtraMap().entrySet()) {
+ map.put(entry.getKey(), ActionBuilders.androidExtraFromProto(entry.getValue()));
+ }
+ return Collections.unmodifiableMap(map);
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static AndroidActivity fromProto(@NonNull ActionProto.AndroidActivity proto) {
+ return new AndroidActivity(proto, null);
+ }
+
+ @NonNull
+ ActionProto.AndroidActivity toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link AndroidActivity} */
+ public static final class Builder {
+ private final ActionProto.AndroidActivity.Builder mImpl =
+ ActionProto.AndroidActivity.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1939606345);
+
+ public Builder() {}
+
+ /** Sets the package name to send the intent to, for example, "com.google.weather". */
+ @NonNull
+ public Builder setPackageName(@NonNull String packageName) {
+ mImpl.setPackageName(packageName);
+ mFingerprint.recordPropertyUpdate(1, packageName.hashCode());
+ return this;
+ }
+
+ /**
+ * Sets the fully qualified class name (including the package) to send the intent to, for
+ * example, "com.google.weather.WeatherOverviewActivity".
+ */
+ @NonNull
+ public Builder setClassName(@NonNull String className) {
+ mImpl.setClassName(className);
+ mFingerprint.recordPropertyUpdate(2, className.hashCode());
+ return this;
+ }
+
+ /** Adds an entry into the extras to be included in the intent. */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @NonNull
+ public Builder addKeyToExtraMapping(@NonNull String key, @NonNull AndroidExtra extra) {
+ mImpl.putKeyToExtra(key, extra.toAndroidExtraProto());
+ mFingerprint.recordPropertyUpdate(
+ key.hashCode(), checkNotNull(extra.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public AndroidActivity build() {
+ return new AndroidActivity(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /**
+ * An action used to launch another activity on the system. This can hold multiple different
+ * underlying action types, which will be picked based on what the underlying runtime believes to
+ * be suitable.
+ */
+ public static final class LaunchAction implements Action {
+ private final ActionProto.LaunchAction mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ LaunchAction(ActionProto.LaunchAction impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets an action to launch an Android activity. Intended for testing purposes only. */
+ @Nullable
+ public AndroidActivity getAndroidActivity() {
+ if (mImpl.hasAndroidActivity()) {
+ return AndroidActivity.fromProto(mImpl.getAndroidActivity());
+ } else {
+ return null;
+ }
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static LaunchAction fromProto(@NonNull ActionProto.LaunchAction proto) {
+ return new LaunchAction(proto, null);
+ }
+
+ @NonNull
+ ActionProto.LaunchAction toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public ActionProto.Action toActionProto() {
+ return ActionProto.Action.newBuilder().setLaunchAction(mImpl).build();
+ }
+
+ /** Builder for {@link LaunchAction}. */
+ public static final class Builder implements Action.Builder {
+ private final ActionProto.LaunchAction.Builder mImpl = ActionProto.LaunchAction.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(175064445);
+
+ public Builder() {}
+
+ /** Sets an action to launch an Android activity. */
+ @NonNull
+ public Builder setAndroidActivity(@NonNull AndroidActivity androidActivity) {
+ mImpl.setAndroidActivity(androidActivity.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(androidActivity.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public LaunchAction build() {
+ return new LaunchAction(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** An action used to load (or reload) the tile contents. */
+ public static final class LoadAction implements Action {
+ private final ActionProto.LoadAction mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ LoadAction(ActionProto.LoadAction impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets the state to load the next tile with. This will be included in the {@link
+ * androidx.wear.tiles.RequestBuilders.TileRequest} sent after this action is invoked by a
+ * {@link androidx.wear.tiles.ModifiersBuilders.Clickable}. Intended for testing purposes only.
+ */
+ @Nullable
+ public State getRequestState() {
+ if (mImpl.hasRequestState()) {
+ return State.fromProto(mImpl.getRequestState());
+ } else {
+ return null;
+ }
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static LoadAction fromProto(@NonNull ActionProto.LoadAction proto) {
+ return new LoadAction(proto, null);
+ }
+
+ @NonNull
+ ActionProto.LoadAction toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public ActionProto.Action toActionProto() {
+ return ActionProto.Action.newBuilder().setLoadAction(mImpl).build();
+ }
+
+ /** Builder for {@link LoadAction}. */
+ public static final class Builder implements Action.Builder {
+ private final ActionProto.LoadAction.Builder mImpl = ActionProto.LoadAction.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1728161517);
+
+ public Builder() {}
+
+ /**
+ * Sets the state to load the next tile with. This will be included in the {@link
+ * androidx.wear.tiles.RequestBuilders.TileRequest} sent after this action is invoked by a
+ * {@link androidx.wear.tiles.ModifiersBuilders.Clickable}.
+ */
+ @NonNull
+ public Builder setRequestState(@NonNull State requestState) {
+ mImpl.setRequestState(requestState.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(requestState.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public LoadAction build() {
+ return new LoadAction(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** Interface defining an action that can be used by a layout element. */
+ public interface Action {
+ /**
+ * Get the protocol buffer representation of this object.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ ActionProto.Action toActionProto();
+
+ /**
+ * Get the fingerprint for this object or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ Fingerprint getFingerprint();
+
+ /** Builder to create {@link Action} objects. */
+ @SuppressLint("StaticFinalBuilder")
+ interface Builder {
+
+ /** Builds an instance with values accumulated in this Builder. */
+ @NonNull
+ Action build();
+ }
+ }
+
+ @NonNull
+ static Action actionFromProto(@NonNull ActionProto.Action proto) {
+ if (proto.hasLaunchAction()) {
+ return LaunchAction.fromProto(proto.getLaunchAction());
+ }
+ if (proto.hasLoadAction()) {
+ return LoadAction.fromProto(proto.getLoadAction());
+ }
+ throw new IllegalStateException("Proto was not a recognised instance of Action");
+ }
+}
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ColorBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ColorBuilders.java
new file mode 100644
index 0000000..f07ee06
--- /dev/null
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ColorBuilders.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2021-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.
+ */
+
+package androidx.wear.protolayout;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
+import androidx.wear.protolayout.proto.ColorProto;
+
+/** Builders for color utilities for layout elements. */
+public final class ColorBuilders {
+ private ColorBuilders() {}
+
+ /** Shortcut for building a {@link ColorProp} using an ARGB value. */
+ @NonNull
+ public static ColorProp argb(@ColorInt int colorArgb) {
+ return new ColorProp.Builder().setArgb(colorArgb).build();
+ }
+
+ /** A property defining a color. */
+ public static final class ColorProp {
+ private final ColorProto.ColorProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ ColorProp(ColorProto.ColorProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the color value, in ARGB format. Intended for testing purposes only. */
+ @ColorInt
+ public int getArgb() {
+ return mImpl.getArgb();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static ColorProp fromProto(@NonNull ColorProto.ColorProp proto) {
+ return new ColorProp(proto, null);
+ }
+
+ @NonNull
+ ColorProto.ColorProp toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link ColorProp} */
+ public static final class Builder {
+ private final ColorProto.ColorProp.Builder mImpl = ColorProto.ColorProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1332287496);
+
+ public Builder() {}
+
+ /** Sets the color value, in ARGB format. */
+ @NonNull
+ public Builder setArgb(@ColorInt int argb) {
+ mImpl.setArgb(argb);
+ mFingerprint.recordPropertyUpdate(1, argb);
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public ColorProp build() {
+ return new ColorProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+}
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/DeviceParametersBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/DeviceParametersBuilders.java
new file mode 100644
index 0000000..b46c5a4
--- /dev/null
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/DeviceParametersBuilders.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2021-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.
+ */
+
+package androidx.wear.protolayout;
+
+import static androidx.annotation.Dimension.DP;
+
+import androidx.annotation.Dimension;
+import androidx.annotation.FloatRange;
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.wear.protolayout.proto.DeviceParametersProto;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** Builders for request messages used to fetch tiles and resources. */
+public final class DeviceParametersBuilders {
+ private DeviceParametersBuilders() {}
+
+ /**
+ * The platform of the device requesting a tile.
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @IntDef({DEVICE_PLATFORM_UNDEFINED, DEVICE_PLATFORM_WEAR_OS})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DevicePlatform {}
+
+ /** Device platform is undefined. */
+ public static final int DEVICE_PLATFORM_UNDEFINED = 0;
+
+ /** Device is a Wear OS device. */
+ public static final int DEVICE_PLATFORM_WEAR_OS = 1;
+
+ /**
+ * The shape of a screen.
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @IntDef({SCREEN_SHAPE_UNDEFINED, SCREEN_SHAPE_ROUND, SCREEN_SHAPE_RECT})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ScreenShape {}
+
+ /** Screen shape is undefined. */
+ public static final int SCREEN_SHAPE_UNDEFINED = 0;
+
+ /** A round screen (typically found on most Wear devices). */
+ public static final int SCREEN_SHAPE_ROUND = 1;
+
+ /** Rectangular screens. */
+ public static final int SCREEN_SHAPE_RECT = 2;
+
+ /**
+ * Parameters describing the device requesting a tile update. This contains physical and logical
+ * characteristics about the device (e.g. screen size and density, etc).
+ */
+ public static final class DeviceParameters {
+ private final DeviceParametersProto.DeviceParameters mImpl;
+
+ private DeviceParameters(DeviceParametersProto.DeviceParameters impl) {
+ this.mImpl = impl;
+ }
+
+ /** Gets width of the device's screen in DP. */
+ @Dimension(unit = DP)
+ public int getScreenWidthDp() {
+ return mImpl.getScreenWidthDp();
+ }
+
+ /** Gets height of the device's screen in DP. */
+ @Dimension(unit = DP)
+ public int getScreenHeightDp() {
+ return mImpl.getScreenHeightDp();
+ }
+
+ /**
+ * Gets density of the display. This value is the scaling factor to get from DP to Pixels (px =
+ * dp * density).
+ */
+ @FloatRange(from = 0.0, fromInclusive = false, toInclusive = false)
+ public float getScreenDensity() {
+ return mImpl.getScreenDensity();
+ }
+
+ /** Gets the platform of the device. */
+ @DevicePlatform
+ public int getDevicePlatform() {
+ return mImpl.getDevicePlatform().getNumber();
+ }
+
+ /** Gets the shape of the device's screen. */
+ @ScreenShape
+ public int getScreenShape() {
+ return mImpl.getScreenShape().getNumber();
+ }
+
+ @NonNull
+ static DeviceParameters fromProto(@NonNull DeviceParametersProto.DeviceParameters proto) {
+ return new DeviceParameters(proto);
+ }
+
+ @NonNull
+ DeviceParametersProto.DeviceParameters toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link DeviceParameters} */
+ public static final class Builder {
+ private final DeviceParametersProto.DeviceParameters.Builder mImpl =
+ DeviceParametersProto.DeviceParameters.newBuilder();
+
+ public Builder() {}
+
+ /** Sets width of the device's screen in DP. */
+ @NonNull
+ public Builder setScreenWidthDp(@Dimension(unit = DP) int screenWidthDp) {
+ mImpl.setScreenWidthDp(screenWidthDp);
+ return this;
+ }
+
+ /** Sets height of the device's screen in DP. */
+ @NonNull
+ public Builder setScreenHeightDp(@Dimension(unit = DP) int screenHeightDp) {
+ mImpl.setScreenHeightDp(screenHeightDp);
+ return this;
+ }
+
+ /**
+ * Sets density of the display. This value is the scaling factor to get from DP to Pixels (px
+ * = dp * density).
+ */
+ @NonNull
+ public Builder setScreenDensity(
+ @FloatRange(from = 0.0, fromInclusive = false, toInclusive = false) float screenDensity) {
+ mImpl.setScreenDensity(screenDensity);
+ return this;
+ }
+
+ /** Sets the platform of the device. */
+ @NonNull
+ public Builder setDevicePlatform(@DevicePlatform int devicePlatform) {
+ mImpl.setDevicePlatform(DeviceParametersProto.DevicePlatform.forNumber(devicePlatform));
+ return this;
+ }
+
+ /** Sets the shape of the device's screen. */
+ @NonNull
+ public Builder setScreenShape(@ScreenShape int screenShape) {
+ mImpl.setScreenShape(DeviceParametersProto.ScreenShape.forNumber(screenShape));
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public DeviceParameters build() {
+ return DeviceParameters.fromProto(mImpl.build());
+ }
+ }
+ }
+}
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/DimensionBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/DimensionBuilders.java
new file mode 100644
index 0000000..e900f65
--- /dev/null
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/DimensionBuilders.java
@@ -0,0 +1,692 @@
+/*
+ * Copyright 2021-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.
+ */
+
+package androidx.wear.protolayout;
+
+import static androidx.annotation.Dimension.DP;
+import static androidx.annotation.Dimension.SP;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.util.DisplayMetrics;
+import androidx.annotation.Dimension;
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
+import androidx.wear.protolayout.proto.DimensionProto;
+
+/** Builders for dimensions for layout elements. */
+public final class DimensionBuilders {
+ private DimensionBuilders() {}
+
+ private static final ExpandedDimensionProp EXPAND = new ExpandedDimensionProp.Builder().build();
+ private static final WrappedDimensionProp WRAP = new WrappedDimensionProp.Builder().build();
+
+ /** Shortcut for building a {@link DpProp} using a measurement in DP. */
+ @NonNull
+ public static DpProp dp(@Dimension(unit = DP) float valueDp) {
+ return new DpProp.Builder().setValue(valueDp).build();
+ }
+
+ /** Shortcut for building a {@link SpProp} using a measurement in SP. */
+ @NonNull
+ public static SpProp sp(@Dimension(unit = SP) float valueSp) {
+ return new SpProp.Builder().setValue(valueSp).build();
+ }
+
+ /** Shortcut for building a {@link EmProp} using a measurement in EM. */
+ @NonNull
+ public static EmProp em(int valueEm) {
+ return new EmProp.Builder().setValue(valueEm).build();
+ }
+
+ /** Shortcut for building a {@link EmProp} using a measurement in EM. */
+ @NonNull
+ public static EmProp em(float valueEm) {
+ return new EmProp.Builder().setValue(valueEm).build();
+ }
+
+ /** Shortcut for building an {@link DegreesProp} using a measurement in degrees. */
+ @NonNull
+ public static DegreesProp degrees(float valueDegrees) {
+ return new DegreesProp.Builder().setValue(valueDegrees).build();
+ }
+
+ /**
+ * Shortcut for building an {@link ExpandedDimensionProp} that will expand to the size of its
+ * parent.
+ */
+ @NonNull
+ public static ExpandedDimensionProp expand() {
+ return EXPAND;
+ }
+
+ /**
+ * Shortcut for building an {@link WrappedDimensionProp} that will shrink to the size of its
+ * children.
+ */
+ @NonNull
+ public static WrappedDimensionProp wrap() {
+ return WRAP;
+ }
+
+ /** A type for linear dimensions, measured in dp. */
+ public static final class DpProp implements ContainerDimension, ImageDimension, SpacerDimension {
+ private final DimensionProto.DpProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ DpProp(DimensionProto.DpProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value, in dp. Intended for testing purposes only. */
+ @Dimension(unit = DP)
+ public float getValue() {
+ return mImpl.getValue();
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static DpProp fromProto(@NonNull DimensionProto.DpProp proto) {
+ return new DpProp(proto, null);
+ }
+
+ @NonNull
+ DimensionProto.DpProp toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public DimensionProto.ContainerDimension toContainerDimensionProto() {
+ return DimensionProto.ContainerDimension.newBuilder().setLinearDimension(mImpl).build();
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public DimensionProto.ImageDimension toImageDimensionProto() {
+ return DimensionProto.ImageDimension.newBuilder().setLinearDimension(mImpl).build();
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public DimensionProto.SpacerDimension toSpacerDimensionProto() {
+ return DimensionProto.SpacerDimension.newBuilder().setLinearDimension(mImpl).build();
+ }
+
+ /** Builder for {@link DpProp}. */
+ public static final class Builder
+ implements ContainerDimension.Builder, ImageDimension.Builder, SpacerDimension.Builder {
+ private final DimensionProto.DpProp.Builder mImpl = DimensionProto.DpProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(752970309);
+
+ public Builder() {}
+
+ /** Sets the value, in dp. */
+ @NonNull
+ public Builder setValue(@Dimension(unit = DP) float value) {
+ mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, Float.floatToIntBits(value));
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public DpProp build() {
+ return new DpProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A type for font sizes, measured in sp. */
+ public static final class SpProp {
+ private final DimensionProto.SpProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ SpProp(DimensionProto.SpProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value, in sp. Intended for testing purposes only. */
+ @Dimension(unit = SP)
+ public float getValue() {
+ return mImpl.getValue();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static SpProp fromProto(@NonNull DimensionProto.SpProp proto) {
+ return new SpProp(proto, null);
+ }
+
+ @NonNull
+ DimensionProto.SpProp toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link SpProp} */
+ public static final class Builder {
+ private final DimensionProto.SpProp.Builder mImpl = DimensionProto.SpProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-2144685857);
+
+ public Builder() {}
+
+ /** Sets the value, in sp. */
+ @NonNull
+ public Builder setValue(@Dimension(unit = SP) float value) {
+ mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(2, Float.floatToIntBits(value));
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public SpProp build() {
+ return new SpProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A type for font spacing, measured in em. */
+ public static final class EmProp {
+ private final DimensionProto.EmProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ EmProp(DimensionProto.EmProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value, in em. Intended for testing purposes only. */
+ public float getValue() {
+ return mImpl.getValue();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static EmProp fromProto(@NonNull DimensionProto.EmProp proto) {
+ return new EmProp(proto, null);
+ }
+
+ @NonNull
+ DimensionProto.EmProp toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link EmProp} */
+ public static final class Builder {
+ private final DimensionProto.EmProp.Builder mImpl = DimensionProto.EmProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1628313311);
+
+ public Builder() {}
+
+ /** Sets the value, in em. */
+ @NonNull
+ public Builder setValue(float value) {
+ mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, Float.floatToIntBits(value));
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public EmProp build() {
+ return new EmProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A type for angular dimensions, measured in degrees. */
+ public static final class DegreesProp {
+ private final DimensionProto.DegreesProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ DegreesProp(DimensionProto.DegreesProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value, in degrees. Intended for testing purposes only. */
+ public float getValue() {
+ return mImpl.getValue();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static DegreesProp fromProto(@NonNull DimensionProto.DegreesProp proto) {
+ return new DegreesProp(proto, null);
+ }
+
+ @NonNull
+ DimensionProto.DegreesProp toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link DegreesProp} */
+ public static final class Builder {
+ private final DimensionProto.DegreesProp.Builder mImpl =
+ DimensionProto.DegreesProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(405060347);
+
+ public Builder() {}
+
+ /** Sets the value, in degrees. */
+ @NonNull
+ public Builder setValue(float value) {
+ mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, Float.floatToIntBits(value));
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public DegreesProp build() {
+ return new DegreesProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /**
+ * A type for a dimension that fills all the space it can (i.e. MATCH_PARENT in Android parlance).
+ */
+ public static final class ExpandedDimensionProp implements ContainerDimension, ImageDimension {
+ private final DimensionProto.ExpandedDimensionProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ ExpandedDimensionProp(
+ DimensionProto.ExpandedDimensionProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static ExpandedDimensionProp fromProto(@NonNull DimensionProto.ExpandedDimensionProp proto) {
+ return new ExpandedDimensionProp(proto, null);
+ }
+
+ @NonNull
+ DimensionProto.ExpandedDimensionProp toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public DimensionProto.ContainerDimension toContainerDimensionProto() {
+ return DimensionProto.ContainerDimension.newBuilder().setExpandedDimension(mImpl).build();
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public DimensionProto.ImageDimension toImageDimensionProto() {
+ return DimensionProto.ImageDimension.newBuilder().setExpandedDimension(mImpl).build();
+ }
+
+ /** Builder for {@link ExpandedDimensionProp}. */
+ public static final class Builder
+ implements ContainerDimension.Builder, ImageDimension.Builder {
+ private final DimensionProto.ExpandedDimensionProp.Builder mImpl =
+ DimensionProto.ExpandedDimensionProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1053378170);
+
+ public Builder() {}
+
+ @Override
+ @NonNull
+ public ExpandedDimensionProp build() {
+ return new ExpandedDimensionProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /**
+ * A type for a dimension that sizes itself to the size of its children (i.e. WRAP_CONTENT in
+ * Android parlance).
+ */
+ public static final class WrappedDimensionProp implements ContainerDimension {
+ private final DimensionProto.WrappedDimensionProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ WrappedDimensionProp(
+ DimensionProto.WrappedDimensionProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static WrappedDimensionProp fromProto(@NonNull DimensionProto.WrappedDimensionProp proto) {
+ return new WrappedDimensionProp(proto, null);
+ }
+
+ @NonNull
+ DimensionProto.WrappedDimensionProp toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public DimensionProto.ContainerDimension toContainerDimensionProto() {
+ return DimensionProto.ContainerDimension.newBuilder().setWrappedDimension(mImpl).build();
+ }
+
+ /** Builder for {@link WrappedDimensionProp}. */
+ public static final class Builder implements ContainerDimension.Builder {
+ private final DimensionProto.WrappedDimensionProp.Builder mImpl =
+ DimensionProto.WrappedDimensionProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-113456542);
+
+ public Builder() {}
+
+ @Override
+ @NonNull
+ public WrappedDimensionProp build() {
+ return new WrappedDimensionProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /**
+ * A type for a dimension that scales itself proportionally to another dimension such that the
+ * aspect ratio defined by the given width and height values is preserved.
+ *
+ * <p>Note that the width and height are unitless; only their ratio is relevant. This allows for
+ * specifying an element's size using common ratios (e.g. width=4, height=3), or to allow an
+ * element to be resized proportionally based on the size of an underlying asset (e.g. an 800x600
+ * image being added to a smaller container and resized accordingly).
+ */
+ public static final class ProportionalDimensionProp implements ImageDimension {
+ private final DimensionProto.ProportionalDimensionProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ ProportionalDimensionProp(
+ DimensionProto.ProportionalDimensionProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets the width to be used when calculating the aspect ratio to preserve. Intended for testing
+ * purposes only.
+ */
+ @IntRange(from = 0)
+ public int getAspectRatioWidth() {
+ return mImpl.getAspectRatioWidth();
+ }
+
+ /**
+ * Gets the height to be used when calculating the aspect ratio ratio to preserve. Intended for
+ * testing purposes only.
+ */
+ @IntRange(from = 0)
+ public int getAspectRatioHeight() {
+ return mImpl.getAspectRatioHeight();
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static ProportionalDimensionProp fromProto(
+ @NonNull DimensionProto.ProportionalDimensionProp proto) {
+ return new ProportionalDimensionProp(proto, null);
+ }
+
+ @NonNull
+ DimensionProto.ProportionalDimensionProp toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public DimensionProto.ImageDimension toImageDimensionProto() {
+ return DimensionProto.ImageDimension.newBuilder().setProportionalDimension(mImpl).build();
+ }
+
+ /** Builder for {@link ProportionalDimensionProp}. */
+ public static final class Builder implements ImageDimension.Builder {
+ private final DimensionProto.ProportionalDimensionProp.Builder mImpl =
+ DimensionProto.ProportionalDimensionProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-2079046835);
+
+ public Builder() {}
+
+ /** Sets the width to be used when calculating the aspect ratio to preserve. */
+ @NonNull
+ public Builder setAspectRatioWidth(@IntRange(from = 0) int aspectRatioWidth) {
+ mImpl.setAspectRatioWidth(aspectRatioWidth);
+ mFingerprint.recordPropertyUpdate(1, aspectRatioWidth);
+ return this;
+ }
+
+ /** Sets the height to be used when calculating the aspect ratio ratio to preserve. */
+ @NonNull
+ public Builder setAspectRatioHeight(@IntRange(from = 0) int aspectRatioHeight) {
+ mImpl.setAspectRatioHeight(aspectRatioHeight);
+ mFingerprint.recordPropertyUpdate(2, aspectRatioHeight);
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public ProportionalDimensionProp build() {
+ return new ProportionalDimensionProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** Interface defining a dimension that can be applied to a container. */
+ public interface ContainerDimension {
+ /**
+ * Get the protocol buffer representation of this object.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ DimensionProto.ContainerDimension toContainerDimensionProto();
+
+ /**
+ * Get the fingerprint for this object or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ Fingerprint getFingerprint();
+
+ /** Builder to create {@link ContainerDimension} objects. */
+ @SuppressLint("StaticFinalBuilder")
+ interface Builder {
+
+ /** Builds an instance with values accumulated in this Builder. */
+ @NonNull
+ ContainerDimension build();
+ }
+ }
+
+ @NonNull
+ static ContainerDimension containerDimensionFromProto(
+ @NonNull DimensionProto.ContainerDimension proto) {
+ if (proto.hasLinearDimension()) {
+ return DpProp.fromProto(proto.getLinearDimension());
+ }
+ if (proto.hasExpandedDimension()) {
+ return ExpandedDimensionProp.fromProto(proto.getExpandedDimension());
+ }
+ if (proto.hasWrappedDimension()) {
+ return WrappedDimensionProp.fromProto(proto.getWrappedDimension());
+ }
+ throw new IllegalStateException("Proto was not a recognised instance of ContainerDimension");
+ }
+
+ /** Interface defining a dimension that can be applied to an image. */
+ public interface ImageDimension {
+ /**
+ * Get the protocol buffer representation of this object.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ DimensionProto.ImageDimension toImageDimensionProto();
+
+ /**
+ * Get the fingerprint for this object or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ Fingerprint getFingerprint();
+
+ /** Builder to create {@link ImageDimension} objects. */
+ @SuppressLint("StaticFinalBuilder")
+ interface Builder {
+
+ /** Builds an instance with values accumulated in this Builder. */
+ @NonNull
+ ImageDimension build();
+ }
+ }
+
+ @NonNull
+ static ImageDimension imageDimensionFromProto(@NonNull DimensionProto.ImageDimension proto) {
+ if (proto.hasLinearDimension()) {
+ return DpProp.fromProto(proto.getLinearDimension());
+ }
+ if (proto.hasExpandedDimension()) {
+ return ExpandedDimensionProp.fromProto(proto.getExpandedDimension());
+ }
+ if (proto.hasProportionalDimension()) {
+ return ProportionalDimensionProp.fromProto(proto.getProportionalDimension());
+ }
+ throw new IllegalStateException("Proto was not a recognised instance of ImageDimension");
+ }
+
+ /** Interface defining a dimension that can be applied to a spacer. */
+ public interface SpacerDimension {
+ /**
+ * Get the protocol buffer representation of this object.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ DimensionProto.SpacerDimension toSpacerDimensionProto();
+
+ /**
+ * Get the fingerprint for this object or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ Fingerprint getFingerprint();
+
+ /** Builder to create {@link SpacerDimension} objects. */
+ @SuppressLint("StaticFinalBuilder")
+ interface Builder {
+
+ /** Builds an instance with values accumulated in this Builder. */
+ @NonNull
+ SpacerDimension build();
+ }
+ }
+
+ @NonNull
+ static SpacerDimension spacerDimensionFromProto(@NonNull DimensionProto.SpacerDimension proto) {
+ if (proto.hasLinearDimension()) {
+ return DpProp.fromProto(proto.getLinearDimension());
+ }
+ throw new IllegalStateException("Proto was not a recognised instance of SpacerDimension");
+ }
+}
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java
new file mode 100644
index 0000000..b123903
--- /dev/null
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java
@@ -0,0 +1,4163 @@
+/*
+ * Copyright 2021-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.
+ */
+
+package androidx.wear.protolayout;
+
+import static androidx.wear.protolayout.expression.Preconditions.checkNotNull;
+
+import android.annotation.SuppressLint;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.ColorBuilders.ColorProp;
+import androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters;
+import androidx.wear.protolayout.DimensionBuilders.ContainerDimension;
+import androidx.wear.protolayout.DimensionBuilders.DegreesProp;
+import androidx.wear.protolayout.DimensionBuilders.DpProp;
+import androidx.wear.protolayout.DimensionBuilders.EmProp;
+import androidx.wear.protolayout.DimensionBuilders.ImageDimension;
+import androidx.wear.protolayout.DimensionBuilders.SpProp;
+import androidx.wear.protolayout.DimensionBuilders.SpacerDimension;
+import androidx.wear.protolayout.ModifiersBuilders.ArcModifiers;
+import androidx.wear.protolayout.ModifiersBuilders.Modifiers;
+import androidx.wear.protolayout.ModifiersBuilders.SpanModifiers;
+import androidx.wear.protolayout.TypeBuilders.BoolProp;
+import androidx.wear.protolayout.TypeBuilders.Int32Prop;
+import androidx.wear.protolayout.TypeBuilders.StringProp;
+import androidx.wear.protolayout.expression.Fingerprint;
+import androidx.wear.protolayout.expression.ProtoLayoutExperimental;
+import androidx.wear.protolayout.proto.AlignmentProto;
+import androidx.wear.protolayout.proto.FingerprintProto;
+import androidx.wear.protolayout.proto.FingerprintProto.TreeFingerprint;
+import androidx.wear.protolayout.proto.LayoutElementProto;
+import androidx.wear.protolayout.proto.TypesProto;
+import androidx.wear.protolayout.protobuf.InvalidProtocolBufferException;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/** Builders for composable layout elements that can be combined together to create renderable
+ * UI */
+public final class LayoutElementBuilders {
+ private LayoutElementBuilders() {}
+
+ /**
+ * The weight to be applied to the font.
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @IntDef({FONT_WEIGHT_UNDEFINED, FONT_WEIGHT_NORMAL, FONT_WEIGHT_MEDIUM, FONT_WEIGHT_BOLD})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FontWeight {}
+
+ /** Font weight is undefined. */
+ public static final int FONT_WEIGHT_UNDEFINED = 0;
+
+ /** Normal font weight. */
+ public static final int FONT_WEIGHT_NORMAL = 400;
+
+ /** Medium font weight. */
+ @ProtoLayoutExperimental public static final int FONT_WEIGHT_MEDIUM = 500;
+
+ /** Bold font weight. */
+ public static final int FONT_WEIGHT_BOLD = 700;
+
+ /**
+ * The variant of a font. Some renderers may use different fonts for title and body text, which
+ * can be selected using this field.
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @IntDef({FONT_VARIANT_UNDEFINED, FONT_VARIANT_TITLE, FONT_VARIANT_BODY})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FontVariant {}
+
+ /** Font variant is undefined. */
+ public static final int FONT_VARIANT_UNDEFINED = 0;
+
+ /** Font variant suited for title text. */
+ public static final int FONT_VARIANT_TITLE = 1;
+
+ /** Font variant suited for body text. */
+ public static final int FONT_VARIANT_BODY = 2;
+
+ /**
+ * The alignment of a {@link SpanImage} within the line height of the surrounding {@link
+ * Spannable}.
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @IntDef({
+ SPAN_VERTICAL_ALIGN_UNDEFINED,
+ SPAN_VERTICAL_ALIGN_BOTTOM,
+ SPAN_VERTICAL_ALIGN_TEXT_BASELINE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SpanVerticalAlignment {}
+
+ /** Alignment is undefined. */
+ public static final int SPAN_VERTICAL_ALIGN_UNDEFINED = 0;
+
+ /**
+ * Align to the bottom of the line (descent of the largest text in this line). If there is no text
+ * in the line containing this image, this will align to the bottom of the line, where the line
+ * height is defined as the height of the largest image in the line.
+ */
+ public static final int SPAN_VERTICAL_ALIGN_BOTTOM = 1;
+
+ /**
+ * Align to the baseline of the text. Note that if the line in the {@link Spannable} which
+ * contains this image does not contain any text, the effects of using this alignment are
+ * undefined.
+ */
+ public static final int SPAN_VERTICAL_ALIGN_TEXT_BASELINE = 2;
+
+ /**
+ * How text that will not fit inside the bounds of a {@link Text} element will be handled.
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @IntDef({TEXT_OVERFLOW_UNDEFINED, TEXT_OVERFLOW_TRUNCATE, TEXT_OVERFLOW_ELLIPSIZE_END})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TextOverflow {}
+
+ /** Overflow behavior is undefined. */
+ public static final int TEXT_OVERFLOW_UNDEFINED = 0;
+
+ /**
+ * Truncate the text to fit inside of the {@link Text} element's bounds. If text is truncated, it
+ * will be truncated on a word boundary.
+ */
+ public static final int TEXT_OVERFLOW_TRUNCATE = 1;
+
+ /**
+ * Truncate the text to fit in the {@link Text} element's bounds, but add an ellipsis (i.e. ...)
+ * to the end of the text if it has been truncated.
+ */
+ public static final int TEXT_OVERFLOW_ELLIPSIZE_END = 2;
+
+ /**
+ * How content which does not match the dimensions of its bounds (e.g. an image resource being
+ * drawn inside an {@link Image}) will be resized to fit its bounds.
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @IntDef({
+ CONTENT_SCALE_MODE_UNDEFINED,
+ CONTENT_SCALE_MODE_FIT,
+ CONTENT_SCALE_MODE_CROP,
+ CONTENT_SCALE_MODE_FILL_BOUNDS
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ContentScaleMode {}
+
+ /** Content scaling is undefined. */
+ public static final int CONTENT_SCALE_MODE_UNDEFINED = 0;
+
+ /**
+ * Content will be scaled to fit inside its bounds, proportionally. As an example, If a 10x5 image
+ * was going to be drawn inside a 50x50 {@link Image} element, the actual image resource would be
+ * drawn as a 50x25 image, centered within the 50x50 bounds.
+ */
+ public static final int CONTENT_SCALE_MODE_FIT = 1;
+
+ /**
+ * Content will be resized proportionally so it completely fills its bounds, and anything outside
+ * of the bounds will be cropped. As an example, if a 10x5 image was going to be drawn inside a
+ * 50x50 {@link Image} element, the image resource would be drawn as a 100x50 image, centered
+ * within its bounds (and with 25px cropped from both the left and right sides).
+ */
+ public static final int CONTENT_SCALE_MODE_CROP = 2;
+
+ /**
+ * Content will be resized to fill its bounds, without taking into account the aspect ratio. If a
+ * 10x5 image was going to be drawn inside a 50x50 {@link Image} element, the image would be drawn
+ * as a 50x50 image, stretched vertically.
+ */
+ public static final int CONTENT_SCALE_MODE_FILL_BOUNDS = 3;
+
+ /** An extensible {@code FontWeight} property. */
+ public static final class FontWeightProp {
+ private final LayoutElementProto.FontWeightProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ FontWeightProp(
+ LayoutElementProto.FontWeightProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value. Intended for testing purposes only. */
+ @FontWeight
+ public int getValue() {
+ return mImpl.getValue().getNumber();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static FontWeightProp fromProto(@NonNull LayoutElementProto.FontWeightProp proto) {
+ return new FontWeightProp(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.FontWeightProp toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link FontWeightProp} */
+ public static final class Builder {
+ private final LayoutElementProto.FontWeightProp.Builder mImpl =
+ LayoutElementProto.FontWeightProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1793388920);
+
+ public Builder() {}
+
+ /** Sets the value. */
+ @NonNull
+ public Builder setValue(@FontWeight int value) {
+ mImpl.setValue(LayoutElementProto.FontWeight.forNumber(value));
+ mFingerprint.recordPropertyUpdate(1, value);
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public FontWeightProp build() {
+ return new FontWeightProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** An extensible {@code FontVariant} property. */
+ @ProtoLayoutExperimental
+ public static final class FontVariantProp {
+ private final LayoutElementProto.FontVariantProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ FontVariantProp(
+ LayoutElementProto.FontVariantProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value. Intended for testing purposes only. */
+ @FontVariant
+ public int getValue() {
+ return mImpl.getValue().getNumber();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static FontVariantProp fromProto(@NonNull LayoutElementProto.FontVariantProp proto) {
+ return new FontVariantProp(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.FontVariantProp toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link FontVariantProp} */
+ public static final class Builder {
+ private final LayoutElementProto.FontVariantProp.Builder mImpl =
+ LayoutElementProto.FontVariantProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-293831500);
+
+ public Builder() {}
+
+ /** Sets the value. */
+ @NonNull
+ public Builder setValue(@FontVariant int value) {
+ mImpl.setValue(LayoutElementProto.FontVariant.forNumber(value));
+ mFingerprint.recordPropertyUpdate(1, value);
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public FontVariantProp build() {
+ return new FontVariantProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** An extensible {@code SpanVerticalAlignment} property. */
+ public static final class SpanVerticalAlignmentProp {
+ private final LayoutElementProto.SpanVerticalAlignmentProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ SpanVerticalAlignmentProp(
+ LayoutElementProto.SpanVerticalAlignmentProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value. Intended for testing purposes only. */
+ @SpanVerticalAlignment
+ public int getValue() {
+ return mImpl.getValue().getNumber();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static SpanVerticalAlignmentProp fromProto(
+ @NonNull LayoutElementProto.SpanVerticalAlignmentProp proto) {
+ return new SpanVerticalAlignmentProp(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.SpanVerticalAlignmentProp toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link SpanVerticalAlignmentProp} */
+ public static final class Builder {
+ private final LayoutElementProto.SpanVerticalAlignmentProp.Builder mImpl =
+ LayoutElementProto.SpanVerticalAlignmentProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1008812329);
+
+ public Builder() {}
+
+ /** Sets the value. */
+ @NonNull
+ public Builder setValue(@SpanVerticalAlignment int value) {
+ mImpl.setValue(LayoutElementProto.SpanVerticalAlignment.forNumber(value));
+ mFingerprint.recordPropertyUpdate(1, value);
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public SpanVerticalAlignmentProp build() {
+ return new SpanVerticalAlignmentProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** The styling of a font (e.g. font size, and metrics). */
+ public static final class FontStyle {
+ private final LayoutElementProto.FontStyle mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ FontStyle(LayoutElementProto.FontStyle impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets the size of the font, in scaled pixels (sp). If not specified, defaults to the size of
+ * the system's "body" font. Intended for testing purposes only.
+ */
+ @Nullable
+ public SpProp getSize() {
+ if (mImpl.hasSize()) {
+ return SpProp.fromProto(mImpl.getSize());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets whether the text should be rendered in a italic typeface. If not specified, defaults to
+ * "false". Intended for testing purposes only.
+ */
+ @Nullable
+ public BoolProp getItalic() {
+ if (mImpl.hasItalic()) {
+ return BoolProp.fromProto(mImpl.getItalic());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets whether the text should be rendered with an underline. If not specified, defaults to
+ * "false". Intended for testing purposes only.
+ */
+ @Nullable
+ public BoolProp getUnderline() {
+ if (mImpl.hasUnderline()) {
+ return BoolProp.fromProto(mImpl.getUnderline());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the text color. If not defined, defaults to white. Intended for testing purposes only.
+ */
+ @Nullable
+ public ColorProp getColor() {
+ if (mImpl.hasColor()) {
+ return ColorProp.fromProto(mImpl.getColor());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the weight of the font. If the provided value is not supported on a platform, the
+ * nearest supported value will be used. If not defined, or when set to an invalid value,
+ * defaults to "normal". Intended for testing purposes only.
+ */
+ @Nullable
+ public FontWeightProp getWeight() {
+ if (mImpl.hasWeight()) {
+ return FontWeightProp.fromProto(mImpl.getWeight());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the text letter-spacing. Positive numbers increase the space between letters while
+ * negative numbers tighten the space. If not specified, defaults to 0. Intended for testing
+ * purposes only.
+ */
+ @Nullable
+ public EmProp getLetterSpacing() {
+ if (mImpl.hasLetterSpacing()) {
+ return EmProp.fromProto(mImpl.getLetterSpacing());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the variant of a font. Some renderers may use different fonts for title and body
+ * text, which can be selected using this field. If not specified, defaults to "body".
+ * Intended for testing purposes only.
+ */
+ @ProtoLayoutExperimental
+ @Nullable
+ public FontVariantProp getVariant() {
+ if (mImpl.hasVariant()) {
+ return FontVariantProp.fromProto(mImpl.getVariant());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static FontStyle fromProto(@NonNull LayoutElementProto.FontStyle proto) {
+ return new FontStyle(proto, null);
+ }
+
+ /**
+ * Returns the internal proto instance.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.FontStyle toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link FontStyle} */
+ public static final class Builder {
+ private final LayoutElementProto.FontStyle.Builder mImpl =
+ LayoutElementProto.FontStyle.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(181264306);
+
+ public Builder() {}
+
+ /**
+ * Sets the size of the font, in scaled pixels (sp). If not specified, defaults to the size of
+ * the system's "body" font.
+ */
+ @NonNull
+ public Builder setSize(@NonNull SpProp size) {
+ mImpl.setSize(size.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(size.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets whether the text should be rendered in a italic typeface. If not specified, defaults
+ * to "false".
+ */
+ @NonNull
+ public Builder setItalic(@NonNull BoolProp italic) {
+ mImpl.setItalic(italic.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(italic.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+ /**
+ * Sets whether the text should be rendered in a italic typeface. If not specified,
+ * defaults to "false".
+ */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @NonNull
+ public Builder setItalic(boolean italic) {
+ mImpl.setItalic(TypesProto.BoolProp.newBuilder().setValue(italic));
+ return this;
+ }
+ /**
+ * Sets whether the text should be rendered with an underline. If not specified, defaults to
+ * "false".
+ */
+ @NonNull
+ public Builder setUnderline(@NonNull BoolProp underline) {
+ mImpl.setUnderline(underline.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(underline.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+ /**
+ * Sets whether the text should be rendered with an underline. If not specified,
+ * defaults to "false".
+ */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @NonNull
+ public Builder setUnderline(boolean underline) {
+ mImpl.setUnderline(TypesProto.BoolProp.newBuilder().setValue(underline));
+ return this;
+ }
+
+ /**
+ * Sets the text color. If not defined, defaults to white.
+ */
+ @NonNull
+ public Builder setColor(@NonNull ColorProp color) {
+ mImpl.setColor(color.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(color.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the weight of the font. If the provided value is not supported on a platform, the
+ * nearest supported value will be used. If not defined, or when set to an invalid value,
+ * defaults to "normal".
+ */
+ @NonNull
+ public Builder setWeight(@NonNull FontWeightProp weight) {
+ mImpl.setWeight(weight.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(weight.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+ /**
+ * Sets the weight of the font. If the provided value is not supported on a platform,
+ * the nearest supported value will be used. If not defined, or when set to an invalid
+ * value, defaults to "normal".
+ */
+ @NonNull
+ public Builder setWeight(@FontWeight int weight) {
+ mImpl.setWeight(
+ LayoutElementProto.FontWeightProp.newBuilder()
+ .setValue(LayoutElementProto.FontWeight.forNumber(weight)));
+ return this;
+ }
+
+ /**
+ * Sets the text letter-spacing. Positive numbers increase the space between letters while
+ * negative numbers tighten the space. If not specified, defaults to 0.
+ */
+ @NonNull
+ public Builder setLetterSpacing(@NonNull EmProp letterSpacing) {
+ mImpl.setLetterSpacing(letterSpacing.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 6, checkNotNull(letterSpacing.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the variant of a font. Some renderers may use different fonts for title and body
+ * text, which can be selected using this field. If not specified, defaults to "body".
+ */
+ @ProtoLayoutExperimental
+ @NonNull
+ public Builder setVariant(@NonNull FontVariantProp variant) {
+ mImpl.setVariant(variant.toProto());
+ return this;
+ }
+ /**
+ * Sets the variant of a font. Some renderers may use different fonts for title and body
+ * text, which can be selected using this field. If not specified, defaults to "body".
+ */
+ @ProtoLayoutExperimental
+ @NonNull
+ public Builder setVariant(@FontVariant int variant) {
+ mImpl.setVariant(
+ LayoutElementProto.FontVariantProp.newBuilder()
+ .setValue(LayoutElementProto.FontVariant.forNumber(variant)));
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public FontStyle build() {
+ return new FontStyle(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** An extensible {@code TextOverflow} property. */
+ public static final class TextOverflowProp {
+ private final LayoutElementProto.TextOverflowProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ TextOverflowProp(
+ LayoutElementProto.TextOverflowProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value. Intended for testing purposes only. */
+ @TextOverflow
+ public int getValue() {
+ return mImpl.getValue().getNumber();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static TextOverflowProp fromProto(@NonNull LayoutElementProto.TextOverflowProp proto) {
+ return new TextOverflowProp(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.TextOverflowProp toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link TextOverflowProp} */
+ public static final class Builder {
+ private final LayoutElementProto.TextOverflowProp.Builder mImpl =
+ LayoutElementProto.TextOverflowProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1183432233);
+
+ public Builder() {}
+
+ /** Sets the value. */
+ @NonNull
+ public Builder setValue(@TextOverflow int value) {
+ mImpl.setValue(LayoutElementProto.TextOverflow.forNumber(value));
+ mFingerprint.recordPropertyUpdate(1, value);
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public TextOverflowProp build() {
+ return new TextOverflowProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A text string. */
+ public static final class Text implements LayoutElement {
+ private final LayoutElementProto.Text mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ Text(LayoutElementProto.Text impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the text to render. Intended for testing purposes only. */
+ @Nullable
+ public StringProp getText() {
+ if (mImpl.hasText()) {
+ return StringProp.fromProto(mImpl.getText());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the style of font to use (size, bold etc). If not specified, defaults to the platform's
+ * default body font. Intended for testing purposes only.
+ */
+ @Nullable
+ public FontStyle getFontStyle() {
+ if (mImpl.hasFontStyle()) {
+ return FontStyle.fromProto(mImpl.getFontStyle());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public Modifiers getModifiers() {
+ if (mImpl.hasModifiers()) {
+ return Modifiers.fromProto(mImpl.getModifiers());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the maximum number of lines that can be represented by the {@link Text} element. If not
+ * defined, the {@link Text} element will be treated as a single-line element. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public Int32Prop getMaxLines() {
+ if (mImpl.hasMaxLines()) {
+ return Int32Prop.fromProto(mImpl.getMaxLines());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets alignment of the text within its bounds. Note that a {@link Text} element will size
+ * itself to wrap its contents, so this option is meaningless for single-line text (for that,
+ * use alignment of the outer container). For multi-line text, however, this will set the
+ * alignment of lines relative to the {@link Text} element bounds. If not defined, defaults to
+ * TEXT_ALIGN_CENTER. Intended for testing purposes only.
+ */
+ @Nullable
+ public TextAlignmentProp getMultilineAlignment() {
+ if (mImpl.hasMultilineAlignment()) {
+ return TextAlignmentProp.fromProto(mImpl.getMultilineAlignment());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets how to handle text which overflows the bound of the {@link Text} element. A {@link Text}
+ * element will grow as large as possible inside its parent container (while still respecting
+ * max_lines); if it cannot grow large enough to render all of its text, the text which cannot
+ * fit inside its container will be truncated. If not defined, defaults to
+ * TEXT_OVERFLOW_TRUNCATE. Intended for testing purposes only.
+ */
+ @Nullable
+ public TextOverflowProp getOverflow() {
+ if (mImpl.hasOverflow()) {
+ return TextOverflowProp.fromProto(mImpl.getOverflow());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the explicit height between lines of text. This is equivalent to the vertical distance
+ * between subsequent baselines. If not specified, defaults the font's recommended interline
+ * spacing. Intended for testing purposes only.
+ */
+ @Nullable
+ public SpProp getLineHeight() {
+ if (mImpl.hasLineHeight()) {
+ return SpProp.fromProto(mImpl.getLineHeight());
+ } else {
+ return null;
+ }
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static Text fromProto(@NonNull LayoutElementProto.Text proto) {
+ return new Text(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.Text toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.LayoutElement toLayoutElementProto() {
+ return LayoutElementProto.LayoutElement.newBuilder().setText(mImpl).build();
+ }
+
+ /** Builder for {@link Text}. */
+ public static final class Builder implements LayoutElement.Builder {
+ private final LayoutElementProto.Text.Builder mImpl = LayoutElementProto.Text.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1976530157);
+
+ public Builder() {}
+
+ /**
+ * Sets the text to render.
+ */
+ @NonNull
+ public Builder setText(@NonNull StringProp text) {
+ mImpl.setText(text.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(text.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+ /** Sets the text to render. */
+ @NonNull
+ public Builder setText(@NonNull String text) {
+ mImpl.setText(TypesProto.StringProp.newBuilder().setValue(text));
+ return this;
+ }
+
+ /**
+ * Sets the style of font to use (size, bold etc). If not specified, defaults to the
+ * platform's default body font.
+ */
+ @NonNull
+ public Builder setFontStyle(@NonNull FontStyle fontStyle) {
+ mImpl.setFontStyle(fontStyle.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(fontStyle.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Sets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. */
+ @NonNull
+ public Builder setModifiers(@NonNull Modifiers modifiers) {
+ mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the maximum number of lines that can be represented by the {@link Text} element. If
+ * not defined, the {@link Text} element will be treated as a single-line element.
+ */
+ @NonNull
+ public Builder setMaxLines(@NonNull Int32Prop maxLines) {
+ mImpl.setMaxLines(maxLines.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(maxLines.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+ /**
+ * Sets the maximum number of lines that can be represented by the {@link Text} element.
+ * If not defined, the {@link Text} element will be treated as a single-line element.
+ */
+ @NonNull
+ public Builder setMaxLines(@IntRange(from = 1) int maxLines) {
+ mImpl.setMaxLines(TypesProto.Int32Prop.newBuilder().setValue(maxLines));
+ return this;
+ }
+
+ /**
+ * Sets alignment of the text within its bounds. Note that a {@link Text} element will size
+ * itself to wrap its contents, so this option is meaningless for single-line text (for that,
+ * use alignment of the outer container). For multi-line text, however, this will set the
+ * alignment of lines relative to the {@link Text} element bounds. If not defined, defaults to
+ * TEXT_ALIGN_CENTER.
+ */
+ @NonNull
+ public Builder setMultilineAlignment(@NonNull TextAlignmentProp multilineAlignment) {
+ mImpl.setMultilineAlignment(multilineAlignment.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(multilineAlignment.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+ /**
+ * Sets alignment of the text within its bounds. Note that a {@link Text} element will
+ * size itself to wrap its contents, so this option is meaningless for single-line text
+ * (for that, use alignment of the outer container). For multi-line text, however, this
+ * will set the alignment of lines relative to the {@link Text} element bounds. If not
+ * defined, defaults to TEXT_ALIGN_CENTER.
+ */
+ @NonNull
+ public Builder setMultilineAlignment(@TextAlignment int multilineAlignment) {
+ mImpl.setMultilineAlignment(
+ AlignmentProto.TextAlignmentProp.newBuilder()
+ .setValue(
+ AlignmentProto.TextAlignment.forNumber(
+ multilineAlignment)));
+ return this;
+ }
+
+ /**
+ * Sets how to handle text which overflows the bound of the {@link Text} element. A {@link
+ * Text} element will grow as large as possible inside its parent container (while still
+ * respecting max_lines); if it cannot grow large enough to render all of its text, the text
+ * which cannot fit inside its container will be truncated. If not defined, defaults to
+ * TEXT_OVERFLOW_TRUNCATE.
+ */
+ @NonNull
+ public Builder setOverflow(@NonNull TextOverflowProp overflow) {
+ mImpl.setOverflow(overflow.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 6, checkNotNull(overflow.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+ /**
+ * Sets how to handle text which overflows the bound of the {@link Text} element. A
+ * {@link Text} element will grow as large as possible inside its parent container
+ * (while still respecting max_lines); if it cannot grow large enough to render all of
+ * its text, the text which cannot fit inside its container will be truncated. If not
+ * defined, defaults to TEXT_OVERFLOW_TRUNCATE.
+ */
+ @NonNull
+ public Builder setOverflow(@TextOverflow int overflow) {
+ mImpl.setOverflow(
+ LayoutElementProto.TextOverflowProp.newBuilder()
+ .setValue(LayoutElementProto.TextOverflow.forNumber(overflow)));
+ return this;
+ }
+
+ /**
+ * Sets the explicit height between lines of text. This is equivalent to the vertical distance
+ * between subsequent baselines. If not specified, defaults the font's recommended interline
+ * spacing.
+ */
+ @NonNull
+ public Builder setLineHeight(@NonNull SpProp lineHeight) {
+ mImpl.setLineHeight(lineHeight.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 7, checkNotNull(lineHeight.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public Text build() {
+ return new Text(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** An extensible {@code ContentScaleMode} property. */
+ public static final class ContentScaleModeProp {
+ private final LayoutElementProto.ContentScaleModeProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ ContentScaleModeProp(
+ LayoutElementProto.ContentScaleModeProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value. Intended for testing purposes only. */
+ @ContentScaleMode
+ public int getValue() {
+ return mImpl.getValue().getNumber();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static ContentScaleModeProp fromProto(@NonNull LayoutElementProto.ContentScaleModeProp proto) {
+ return new ContentScaleModeProp(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.ContentScaleModeProp toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link ContentScaleModeProp} */
+ public static final class Builder {
+ private final LayoutElementProto.ContentScaleModeProp.Builder mImpl =
+ LayoutElementProto.ContentScaleModeProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-893830536);
+
+ public Builder() {}
+
+ /** Sets the value. */
+ @NonNull
+ public Builder setValue(@ContentScaleMode int value) {
+ mImpl.setValue(LayoutElementProto.ContentScaleMode.forNumber(value));
+ mFingerprint.recordPropertyUpdate(1, value);
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public ContentScaleModeProp build() {
+ return new ContentScaleModeProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** Filtering parameters used for images. This can be used to apply a color tint to images. */
+ public static final class ColorFilter {
+ private final LayoutElementProto.ColorFilter mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ ColorFilter(LayoutElementProto.ColorFilter impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets the tint color to use. If specified, the image will be tinted, using SRC_IN blending
+ * (that is, all color information will be stripped from the target image, and only the alpha
+ * channel will be blended with the requested color).
+ *
+ * <p>Note that only Android image resources can be tinted; Inline images will not be tinted,
+ * and this property will have no effect. Intended for testing purposes only.
+ */
+ @Nullable
+ public ColorProp getTint() {
+ if (mImpl.hasTint()) {
+ return ColorProp.fromProto(mImpl.getTint());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static ColorFilter fromProto(@NonNull LayoutElementProto.ColorFilter proto) {
+ return new ColorFilter(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.ColorFilter toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link ColorFilter} */
+ public static final class Builder {
+ private final LayoutElementProto.ColorFilter.Builder mImpl =
+ LayoutElementProto.ColorFilter.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(181311326);
+
+ public Builder() {}
+
+ /**
+ * Sets the tint color to use. If specified, the image will be tinted, using SRC_IN blending
+ * (that is, all color information will be stripped from the target image, and only the alpha
+ * channel will be blended with the requested color).
+ *
+ * <p>Note that only Android image resources can be tinted; Inline images will not be tinted,
+ * and this property will have no effect.
+ */
+ @NonNull
+ public Builder setTint(@NonNull ColorProp tint) {
+ mImpl.setTint(tint.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(tint.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public ColorFilter build() {
+ return new ColorFilter(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /**
+ * An image.
+ *
+ * <p>Images used in this element must exist in the resource bundle that corresponds to this
+ * layout. Images must have their dimension specified, and will be rendered at this width and
+ * height, regardless of their native dimension.
+ */
+ public static final class Image implements LayoutElement {
+ private final LayoutElementProto.Image mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ Image(LayoutElementProto.Image impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets the resource_id of the image to render. This must exist in the supplied resource bundle.
+ * Intended for testing purposes only.
+ */
+ @Nullable
+ public StringProp getResourceId() {
+ if (mImpl.hasResourceId()) {
+ return StringProp.fromProto(mImpl.getResourceId());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the width of this image. If not defined, the image will not be rendered. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public ImageDimension getWidth() {
+ if (mImpl.hasWidth()) {
+ return DimensionBuilders.imageDimensionFromProto(mImpl.getWidth());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the height of this image. If not defined, the image will not be rendered. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public ImageDimension getHeight() {
+ if (mImpl.hasHeight()) {
+ return DimensionBuilders.imageDimensionFromProto(mImpl.getHeight());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets how to scale the image resource inside the bounds specified by width/height if its size
+ * does not match those bounds. Defaults to CONTENT_SCALE_MODE_FIT. Intended for testing
+ * purposes only.
+ */
+ @Nullable
+ public ContentScaleModeProp getContentScaleMode() {
+ if (mImpl.hasContentScaleMode()) {
+ return ContentScaleModeProp.fromProto(mImpl.getContentScaleMode());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public Modifiers getModifiers() {
+ if (mImpl.hasModifiers()) {
+ return Modifiers.fromProto(mImpl.getModifiers());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets filtering parameters for this image. If not specified, defaults to no filtering.
+ * Intended for testing purposes only.
+ */
+ @Nullable
+ public ColorFilter getColorFilter() {
+ if (mImpl.hasColorFilter()) {
+ return ColorFilter.fromProto(mImpl.getColorFilter());
+ } else {
+ return null;
+ }
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static Image fromProto(@NonNull LayoutElementProto.Image proto) {
+ return new Image(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.Image toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.LayoutElement toLayoutElementProto() {
+ return LayoutElementProto.LayoutElement.newBuilder().setImage(mImpl).build();
+ }
+
+ /** Builder for {@link Image}. */
+ public static final class Builder implements LayoutElement.Builder {
+ private final LayoutElementProto.Image.Builder mImpl = LayoutElementProto.Image.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-543078544);
+
+ public Builder() {}
+
+ /**
+ * Sets the resource_id of the image to render. This must exist in the supplied resource
+ * bundle.
+ */
+ @NonNull
+ public Builder setResourceId(@NonNull StringProp resourceId) {
+ mImpl.setResourceId(resourceId.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(resourceId.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+ /**
+ * Sets the resource_id of the image to render. This must exist in the supplied resource
+ * bundle.
+ */
+ @NonNull
+ public Builder setResourceId(@NonNull String resourceId) {
+ mImpl.setResourceId(TypesProto.StringProp.newBuilder().setValue(resourceId));
+ return this;
+ }
+
+ /**
+ * Sets the width of this image. If not defined, the image will not be rendered.
+ */
+ @NonNull
+ public Builder setWidth(@NonNull ImageDimension width) {
+ mImpl.setWidth(width.toImageDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(width.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the height of this image. If not defined, the image will not be rendered.
+ */
+ @NonNull
+ public Builder setHeight(@NonNull ImageDimension height) {
+ mImpl.setHeight(height.toImageDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(height.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets how to scale the image resource inside the bounds specified by width/height if its
+ * size does not match those bounds. Defaults to CONTENT_SCALE_MODE_FIT.
+ */
+ @NonNull
+ public Builder setContentScaleMode(@NonNull ContentScaleModeProp contentScaleMode) {
+ mImpl.setContentScaleMode(contentScaleMode.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(contentScaleMode.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+ /**
+ * Sets how to scale the image resource inside the bounds specified by width/height if
+ * its size does not match those bounds. Defaults to CONTENT_SCALE_MODE_FIT.
+ */
+ @NonNull
+ public Builder setContentScaleMode(@ContentScaleMode int contentScaleMode) {
+ mImpl.setContentScaleMode(
+ LayoutElementProto.ContentScaleModeProp.newBuilder()
+ .setValue(
+ LayoutElementProto.ContentScaleMode.forNumber(
+ contentScaleMode)));
+ return this;
+ }
+
+ /** Sets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. */
+ @NonNull
+ public Builder setModifiers(@NonNull Modifiers modifiers) {
+ mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Sets filtering parameters for this image. If not specified, defaults to no filtering. */
+ @NonNull
+ public Builder setColorFilter(@NonNull ColorFilter colorFilter) {
+ mImpl.setColorFilter(colorFilter.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 6, checkNotNull(colorFilter.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public Image build() {
+ return new Image(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A simple spacer, typically used to provide padding between adjacent elements. */
+ public static final class Spacer implements LayoutElement {
+ private final LayoutElementProto.Spacer mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ Spacer(LayoutElementProto.Spacer impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets the width of this {@link Spacer}. When this is added as the direct child of an {@link
+ * Arc}, this must be specified as an angular dimension, otherwise a linear dimension must be
+ * used. If not defined, defaults to 0. Intended for testing purposes only.
+ */
+ @Nullable
+ public SpacerDimension getWidth() {
+ if (mImpl.hasWidth()) {
+ return DimensionBuilders.spacerDimensionFromProto(mImpl.getWidth());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the height of this spacer. If not defined, defaults to 0. Intended for testing purposes
+ * only.
+ */
+ @Nullable
+ public SpacerDimension getHeight() {
+ if (mImpl.hasHeight()) {
+ return DimensionBuilders.spacerDimensionFromProto(mImpl.getHeight());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public Modifiers getModifiers() {
+ if (mImpl.hasModifiers()) {
+ return Modifiers.fromProto(mImpl.getModifiers());
+ } else {
+ return null;
+ }
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static Spacer fromProto(@NonNull LayoutElementProto.Spacer proto) {
+ return new Spacer(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.Spacer toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.LayoutElement toLayoutElementProto() {
+ return LayoutElementProto.LayoutElement.newBuilder().setSpacer(mImpl).build();
+ }
+
+ /** Builder for {@link Spacer}. */
+ public static final class Builder implements LayoutElement.Builder {
+ private final LayoutElementProto.Spacer.Builder mImpl =
+ LayoutElementProto.Spacer.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1748084575);
+
+ public Builder() {}
+
+ /**
+ * Sets the width of this {@link Spacer}. When this is added as the direct child of an {@link
+ * Arc}, this must be specified as an angular dimension, otherwise a linear dimension must be
+ * used. If not defined, defaults to 0.
+ */
+ @NonNull
+ public Builder setWidth(@NonNull SpacerDimension width) {
+ mImpl.setWidth(width.toSpacerDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(width.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the height of this spacer. If not defined, defaults to 0.
+ */
+ @NonNull
+ public Builder setHeight(@NonNull SpacerDimension height) {
+ mImpl.setHeight(height.toSpacerDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(height.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Sets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. */
+ @NonNull
+ public Builder setModifiers(@NonNull Modifiers modifiers) {
+ mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+
+ @Override
+ @NonNull
+ public Spacer build() {
+ return new Spacer(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /**
+ * A container which stacks all of its children on top of one another. This also allows to add a
+ * background color, or to have a border around them with some padding.
+ */
+ public static final class Box implements LayoutElement {
+ private final LayoutElementProto.Box mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ Box(LayoutElementProto.Box impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the child element(s) to wrap. Intended for testing purposes only. */
+ @NonNull
+ public List<LayoutElement> getContents() {
+ List<LayoutElement> list = new ArrayList<>();
+ for (LayoutElementProto.LayoutElement item : mImpl.getContentsList()) {
+ list.add(LayoutElementBuilders.layoutElementFromProto(item));
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ /**
+ * Gets the height of this {@link Box}. If not defined, this will size itself to fit all of its
+ * children (i.e. a WrappedDimension). Intended for testing purposes only.
+ */
+ @Nullable
+ public ContainerDimension getHeight() {
+ if (mImpl.hasHeight()) {
+ return DimensionBuilders.containerDimensionFromProto(mImpl.getHeight());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the width of this {@link Box}. If not defined, this will size itself to fit all of its
+ * children (i.e. a WrappedDimension). Intended for testing purposes only.
+ */
+ @Nullable
+ public ContainerDimension getWidth() {
+ if (mImpl.hasWidth()) {
+ return DimensionBuilders.containerDimensionFromProto(mImpl.getWidth());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the horizontal alignment of the element inside this {@link Box}. If not defined,
+ * defaults to HORIZONTAL_ALIGN_CENTER. Intended for testing purposes only.
+ */
+ @Nullable
+ public HorizontalAlignmentProp getHorizontalAlignment() {
+ if (mImpl.hasHorizontalAlignment()) {
+ return HorizontalAlignmentProp.fromProto(mImpl.getHorizontalAlignment());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the vertical alignment of the element inside this {@link Box}. If not defined, defaults
+ * to VERTICAL_ALIGN_CENTER. Intended for testing purposes only.
+ */
+ @Nullable
+ public VerticalAlignmentProp getVerticalAlignment() {
+ if (mImpl.hasVerticalAlignment()) {
+ return VerticalAlignmentProp.fromProto(mImpl.getVerticalAlignment());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public Modifiers getModifiers() {
+ if (mImpl.hasModifiers()) {
+ return Modifiers.fromProto(mImpl.getModifiers());
+ } else {
+ return null;
+ }
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static Box fromProto(@NonNull LayoutElementProto.Box proto) {
+ return new Box(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.Box toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.LayoutElement toLayoutElementProto() {
+ return LayoutElementProto.LayoutElement.newBuilder().setBox(mImpl).build();
+ }
+
+ /** Builder for {@link Box}. */
+ public static final class Builder implements LayoutElement.Builder {
+ private final LayoutElementProto.Box.Builder mImpl = LayoutElementProto.Box.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1881256071);
+
+ public Builder() {}
+
+ /** Adds one item to the child element(s) to wrap. */
+ @NonNull
+ public Builder addContent(@NonNull LayoutElement content) {
+ mImpl.addContents(content.toLayoutElementProto());
+ mFingerprint.addChildNode(checkNotNull(content.getFingerprint()));
+ return this;
+ }
+
+ /**
+ * Sets the height of this {@link Box}. If not defined, this will size itself to fit all of
+ * its children (i.e. a WrappedDimension).
+ */
+ @NonNull
+ public Builder setHeight(@NonNull ContainerDimension height) {
+ mImpl.setHeight(height.toContainerDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(height.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the width of this {@link Box}. If not defined, this will size itself to fit all of its
+ * children (i.e. a WrappedDimension).
+ */
+ @NonNull
+ public Builder setWidth(@NonNull ContainerDimension width) {
+ mImpl.setWidth(width.toContainerDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(width.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the horizontal alignment of the element inside this {@link Box}. If not defined,
+ * defaults to HORIZONTAL_ALIGN_CENTER.
+ */
+ @NonNull
+ public Builder setHorizontalAlignment(@NonNull HorizontalAlignmentProp horizontalAlignment) {
+ mImpl.setHorizontalAlignment(horizontalAlignment.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(horizontalAlignment.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the horizontal alignment of the element inside this {@link Box}. If not defined,
+ * defaults to HORIZONTAL_ALIGN_CENTER.
+ */
+ @NonNull
+ public Builder setHorizontalAlignment(@HorizontalAlignment int horizontalAlignment) {
+ mImpl.setHorizontalAlignment(
+ AlignmentProto.HorizontalAlignmentProp.newBuilder()
+ .setValue(
+ AlignmentProto.HorizontalAlignment.forNumber(
+ horizontalAlignment)));
+ return this;
+ }
+
+ /**
+ * Sets the vertical alignment of the element inside this {@link Box}. If not defined,
+ * defaults to VERTICAL_ALIGN_CENTER.
+ */
+ @NonNull
+ public Builder setVerticalAlignment(@NonNull VerticalAlignmentProp verticalAlignment) {
+ mImpl.setVerticalAlignment(verticalAlignment.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(verticalAlignment.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+ /**
+ * Sets the vertical alignment of the element inside this {@link Box}. If not defined,
+ * defaults to VERTICAL_ALIGN_CENTER.
+ */
+ @NonNull
+ public Builder setVerticalAlignment(@VerticalAlignment int verticalAlignment) {
+ mImpl.setVerticalAlignment(
+ AlignmentProto.VerticalAlignmentProp.newBuilder()
+ .setValue(
+ AlignmentProto.VerticalAlignment.forNumber(
+ verticalAlignment)));
+ return this;
+ }
+
+ /** Sets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. */
+ @NonNull
+ public Builder setModifiers(@NonNull Modifiers modifiers) {
+ mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 6, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+
+ @Override
+ @NonNull
+ public Box build() {
+ return new Box(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /**
+ * A portion of text which can be added to a {@link Span}. Two different {@link SpanText} elements
+ * on the same line will be aligned to the same baseline, regardless of the size of each {@link
+ * SpanText}.
+ */
+ public static final class SpanText implements Span {
+ private final LayoutElementProto.SpanText mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ SpanText(LayoutElementProto.SpanText impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the text to render. Intended for testing purposes only. */
+ @Nullable
+ public StringProp getText() {
+ if (mImpl.hasText()) {
+ return StringProp.fromProto(mImpl.getText());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the style of font to use (size, bold etc). If not specified, defaults to the platform's
+ * default body font. Intended for testing purposes only.
+ */
+ @Nullable
+ public FontStyle getFontStyle() {
+ if (mImpl.hasFontStyle()) {
+ return FontStyle.fromProto(mImpl.getFontStyle());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public SpanModifiers getModifiers() {
+ if (mImpl.hasModifiers()) {
+ return SpanModifiers.fromProto(mImpl.getModifiers());
+ } else {
+ return null;
+ }
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static SpanText fromProto(@NonNull LayoutElementProto.SpanText proto) {
+ return new SpanText(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.SpanText toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.Span toSpanProto() {
+ return LayoutElementProto.Span.newBuilder().setText(mImpl).build();
+ }
+
+ /** Builder for {@link SpanText}. */
+ public static final class Builder implements Span.Builder {
+ private final LayoutElementProto.SpanText.Builder mImpl =
+ LayoutElementProto.SpanText.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-221774557);
+
+ public Builder() {}
+
+ /**
+ * Sets the text to render.
+ */
+ @NonNull
+ public Builder setText(@NonNull StringProp text) {
+ mImpl.setText(text.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(text.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+ /** Sets the text to render. */
+ @NonNull
+ public Builder setText(@NonNull String text) {
+ mImpl.setText(TypesProto.StringProp.newBuilder().setValue(text));
+ return this;
+ }
+
+ /**
+ * Sets the style of font to use (size, bold etc). If not specified, defaults to the
+ * platform's default body font.
+ */
+ @NonNull
+ public Builder setFontStyle(@NonNull FontStyle fontStyle) {
+ mImpl.setFontStyle(fontStyle.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(fontStyle.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Sets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. */
+ @NonNull
+ public Builder setModifiers(@NonNull SpanModifiers modifiers) {
+ mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public SpanText build() {
+ return new SpanText(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** An image which can be added to a {@link Span}. */
+ public static final class SpanImage implements Span {
+ private final LayoutElementProto.SpanImage mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ SpanImage(LayoutElementProto.SpanImage impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets the resource_id of the image to render. This must exist in the supplied resource bundle.
+ * Intended for testing purposes only.
+ */
+ @Nullable
+ public StringProp getResourceId() {
+ if (mImpl.hasResourceId()) {
+ return StringProp.fromProto(mImpl.getResourceId());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the width of this image. If not defined, the image will not be rendered. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public DpProp getWidth() {
+ if (mImpl.hasWidth()) {
+ return DpProp.fromProto(mImpl.getWidth());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the height of this image. If not defined, the image will not be rendered. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public DpProp getHeight() {
+ if (mImpl.hasHeight()) {
+ return DpProp.fromProto(mImpl.getHeight());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public SpanModifiers getModifiers() {
+ if (mImpl.hasModifiers()) {
+ return SpanModifiers.fromProto(mImpl.getModifiers());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets alignment of this image within the line height of the surrounding {@link Spannable}. If
+ * undefined, defaults to SPAN_VERTICAL_ALIGN_BOTTOM. Intended for testing purposes only.
+ */
+ @Nullable
+ public SpanVerticalAlignmentProp getAlignment() {
+ if (mImpl.hasAlignment()) {
+ return SpanVerticalAlignmentProp.fromProto(mImpl.getAlignment());
+ } else {
+ return null;
+ }
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static SpanImage fromProto(@NonNull LayoutElementProto.SpanImage proto) {
+ return new SpanImage(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.SpanImage toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.Span toSpanProto() {
+ return LayoutElementProto.Span.newBuilder().setImage(mImpl).build();
+ }
+
+ /** Builder for {@link SpanImage}. */
+ public static final class Builder implements Span.Builder {
+ private final LayoutElementProto.SpanImage.Builder mImpl =
+ LayoutElementProto.SpanImage.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(502289772);
+
+ public Builder() {}
+
+ /**
+ * Sets the resource_id of the image to render. This must exist in the supplied resource
+ * bundle.
+ */
+ @NonNull
+ public Builder setResourceId(@NonNull StringProp resourceId) {
+ mImpl.setResourceId(resourceId.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(resourceId.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+ /**
+ * Sets the resource_id of the image to render. This must exist in the supplied resource
+ * bundle.
+ */
+ @NonNull
+ public Builder setResourceId(@NonNull String resourceId) {
+ mImpl.setResourceId(TypesProto.StringProp.newBuilder().setValue(resourceId));
+ return this;
+ }
+
+ /**
+ * Sets the width of this image. If not defined, the image will not be rendered.
+ */
+ @NonNull
+ public Builder setWidth(@NonNull DpProp width) {
+ mImpl.setWidth(width.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(width.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the height of this image. If not defined, the image will not be rendered.
+ */
+ @NonNull
+ public Builder setHeight(@NonNull DpProp height) {
+ mImpl.setHeight(height.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(height.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Sets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. */
+ @NonNull
+ public Builder setModifiers(@NonNull SpanModifiers modifiers) {
+ mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets alignment of this image within the line height of the surrounding {@link Spannable}.
+ * If undefined, defaults to SPAN_VERTICAL_ALIGN_BOTTOM.
+ */
+ @NonNull
+ public Builder setAlignment(@NonNull SpanVerticalAlignmentProp alignment) {
+ mImpl.setAlignment(alignment.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(alignment.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+ /**
+ * Sets alignment of this image within the line height of the surrounding {@link
+ * Spannable}. If undefined, defaults to SPAN_VERTICAL_ALIGN_BOTTOM.
+ */
+ @NonNull
+ public Builder setAlignment(@SpanVerticalAlignment int alignment) {
+ mImpl.setAlignment(
+ LayoutElementProto.SpanVerticalAlignmentProp.newBuilder()
+ .setValue(
+ LayoutElementProto.SpanVerticalAlignment.forNumber(
+ alignment)));
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public SpanImage build() {
+ return new SpanImage(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /**
+ * Interface defining a single {@link Span}. Each {@link Span} forms part of a larger {@link
+ * Spannable} widget. At the moment, the only widgets which can be added to {@link Spannable}
+ * containers are {@link SpanText} and {@link SpanImage} elements.
+ */
+ public interface Span {
+ /**
+ * Get the protocol buffer representation of this object.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ LayoutElementProto.Span toSpanProto();
+
+ /**
+ * Get the fingerprint for this object or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ Fingerprint getFingerprint();
+
+ /** Builder to create {@link Span} objects. */
+ @SuppressLint("StaticFinalBuilder")
+ interface Builder {
+
+ /** Builds an instance with values accumulated in this Builder. */
+ @NonNull
+ Span build();
+ }
+ }
+
+ @NonNull
+ static Span spanFromProto(@NonNull LayoutElementProto.Span proto) {
+ if (proto.hasText()) {
+ return SpanText.fromProto(proto.getText());
+ }
+ if (proto.hasImage()) {
+ return SpanImage.fromProto(proto.getImage());
+ }
+ throw new IllegalStateException("Proto was not a recognised instance of Span");
+ }
+
+ /**
+ * A container of {@link Span} elements. Currently, this supports {@link SpanImage} and {@link
+ * SpanText} elements, where each individual {@link Span} can have different styling applied to it
+ * but the resulting text will flow naturally. This allows sections of a paragraph of text to have
+ * different styling applied to it, for example, making one or two words bold or italic.
+ */
+ public static final class Spannable implements LayoutElement {
+ private final LayoutElementProto.Spannable mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ Spannable(LayoutElementProto.Spannable impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets the {@link Span} elements that form this {@link Spannable}. Intended for testing
+ * purposes only.
+ */
+ @NonNull
+ public List<Span> getSpans() {
+ List<Span> list = new ArrayList<>();
+ for (LayoutElementProto.Span item : mImpl.getSpansList()) {
+ list.add(LayoutElementBuilders.spanFromProto(item));
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ /**
+ * Gets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public Modifiers getModifiers() {
+ if (mImpl.hasModifiers()) {
+ return Modifiers.fromProto(mImpl.getModifiers());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the maximum number of lines that can be represented by the {@link Spannable} element. If
+ * not defined, the {@link Spannable} element will be treated as a single-line element. Intended
+ * for testing purposes only.
+ */
+ @Nullable
+ public Int32Prop getMaxLines() {
+ if (mImpl.hasMaxLines()) {
+ return Int32Prop.fromProto(mImpl.getMaxLines());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets alignment of the {@link Spannable} content within its bounds. Note that a {@link
+ * Spannable} element will size itself to wrap its contents, so this option is meaningless for
+ * single-line content (for that, use alignment of the outer container). For multi-line content,
+ * however, this will set the alignment of lines relative to the {@link Spannable} element
+ * bounds. If not defined, defaults to TEXT_ALIGN_CENTER. Intended for testing purposes only.
+ */
+ @Nullable
+ public HorizontalAlignmentProp getMultilineAlignment() {
+ if (mImpl.hasMultilineAlignment()) {
+ return HorizontalAlignmentProp.fromProto(mImpl.getMultilineAlignment());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets how to handle content which overflows the bound of the {@link Spannable} element. A
+ * {@link Spannable} element will grow as large as possible inside its parent container (while
+ * still respecting max_lines); if it cannot grow large enough to render all of its content, the
+ * content which cannot fit inside its container will be truncated. If not defined, defaults to
+ * TEXT_OVERFLOW_TRUNCATE. Intended for testing purposes only.
+ */
+ @Nullable
+ public TextOverflowProp getOverflow() {
+ if (mImpl.hasOverflow()) {
+ return TextOverflowProp.fromProto(mImpl.getOverflow());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the explicit height between lines of text. This is equivalent to the vertical distance
+ * between subsequent baselines. If not specified, defaults the font's recommended interline
+ * spacing. Intended for testing purposes only.
+ */
+ @Nullable
+ public SpProp getLineHeight() {
+ if (mImpl.hasLineHeight()) {
+ return SpProp.fromProto(mImpl.getLineHeight());
+ } else {
+ return null;
+ }
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static Spannable fromProto(@NonNull LayoutElementProto.Spannable proto) {
+ return new Spannable(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.Spannable toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.LayoutElement toLayoutElementProto() {
+ return LayoutElementProto.LayoutElement.newBuilder().setSpannable(mImpl).build();
+ }
+
+ /** Builder for {@link Spannable}. */
+ public static final class Builder implements LayoutElement.Builder {
+ private final LayoutElementProto.Spannable.Builder mImpl =
+ LayoutElementProto.Spannable.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1690284372);
+
+ public Builder() {}
+
+ /** Adds one item to the {@link Span} elements that form this {@link Spannable}. */
+ @NonNull
+ public Builder addSpan(@NonNull Span span) {
+ mImpl.addSpans(span.toSpanProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(span.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Sets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. */
+ @NonNull
+ public Builder setModifiers(@NonNull Modifiers modifiers) {
+ mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the maximum number of lines that can be represented by the {@link Spannable} element.
+ * If not defined, the {@link Spannable} element will be treated as a single-line element.
+ */
+ @NonNull
+ public Builder setMaxLines(@NonNull Int32Prop maxLines) {
+ mImpl.setMaxLines(maxLines.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(maxLines.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+ /**
+ * Sets the maximum number of lines that can be represented by the {@link Spannable}
+ * element. If not defined, the {@link Spannable} element will be treated as a
+ * single-line element.
+ */
+ @NonNull
+ public Builder setMaxLines(@IntRange(from = 1) int maxLines) {
+ mImpl.setMaxLines(TypesProto.Int32Prop.newBuilder().setValue(maxLines));
+ return this;
+ }
+
+ /**
+ * Sets alignment of the {@link Spannable} content within its bounds. Note that a {@link
+ * Spannable} element will size itself to wrap its contents, so this option is meaningless for
+ * single-line content (for that, use alignment of the outer container). For multi-line
+ * content, however, this will set the alignment of lines relative to the {@link Spannable}
+ * element bounds. If not defined, defaults to TEXT_ALIGN_CENTER.
+ */
+ @NonNull
+ public Builder setMultilineAlignment(@NonNull HorizontalAlignmentProp multilineAlignment) {
+ mImpl.setMultilineAlignment(multilineAlignment.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(multilineAlignment.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+ /**
+ * Sets alignment of the {@link Spannable} content within its bounds. Note that a {@link
+ * Spannable} element will size itself to wrap its contents, so this option is
+ * meaningless for single-line content (for that, use alignment of the outer container).
+ * For multi-line content, however, this will set the alignment of lines relative to the
+ * {@link Spannable} element bounds. If not defined, defaults to TEXT_ALIGN_CENTER.
+ */
+ @NonNull
+ public Builder setMultilineAlignment(@HorizontalAlignment int multilineAlignment) {
+ mImpl.setMultilineAlignment(
+ AlignmentProto.HorizontalAlignmentProp.newBuilder()
+ .setValue(
+ AlignmentProto.HorizontalAlignment.forNumber(
+ multilineAlignment)));
+ return this;
+ }
+
+ /**
+ * Sets how to handle content which overflows the bound of the {@link Spannable} element. A
+ * {@link Spannable} element will grow as large as possible inside its parent container (while
+ * still respecting max_lines); if it cannot grow large enough to render all of its content,
+ * the content which cannot fit inside its container will be truncated. If not defined,
+ * defaults to TEXT_OVERFLOW_TRUNCATE.
+ */
+ @NonNull
+ public Builder setOverflow(@NonNull TextOverflowProp overflow) {
+ mImpl.setOverflow(overflow.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(overflow.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+ /**
+ * Sets how to handle content which overflows the bound of the {@link Spannable}
+ * element. A {@link Spannable} element will grow as large as possible inside its parent
+ * container (while still respecting max_lines); if it cannot grow large enough to
+ * render all of its content, the content which cannot fit inside its container will be
+ * truncated. If not defined, defaults to TEXT_OVERFLOW_TRUNCATE.
+ */
+ @NonNull
+ public Builder setOverflow(@TextOverflow int overflow) {
+ mImpl.setOverflow(
+ LayoutElementProto.TextOverflowProp.newBuilder()
+ .setValue(LayoutElementProto.TextOverflow.forNumber(overflow)));
+ return this;
+ }
+
+ /**
+ * Sets the explicit height between lines of text. This is equivalent to the vertical distance
+ * between subsequent baselines. If not specified, defaults the font's recommended interline
+ * spacing.
+ */
+ @NonNull
+ public Builder setLineHeight(@NonNull SpProp lineHeight) {
+ mImpl.setLineHeight(lineHeight.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 7, checkNotNull(lineHeight.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public Spannable build() {
+ return new Spannable(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /**
+ * A column of elements. Each child element will be laid out vertically, one after another (i.e.
+ * stacking down). This element will size itself to the smallest size required to hold all of its
+ * children (e.g. if it contains three elements sized 10x10, 20x20 and 30x30, the resulting column
+ * will be 30x60).
+ *
+ * <p>If specified, horizontal_alignment can be used to control the gravity inside the container,
+ * affecting the horizontal placement of children whose width are smaller than the resulting
+ * column width.
+ */
+ public static final class Column implements LayoutElement {
+ private final LayoutElementProto.Column mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ Column(LayoutElementProto.Column impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets the list of child elements to place inside this {@link Column}. Intended for testing
+ * purposes only.
+ */
+ @NonNull
+ public List<LayoutElement> getContents() {
+ List<LayoutElement> list = new ArrayList<>();
+ for (LayoutElementProto.LayoutElement item : mImpl.getContentsList()) {
+ list.add(LayoutElementBuilders.layoutElementFromProto(item));
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ /**
+ * Gets the horizontal alignment of elements inside this column, if they are narrower than the
+ * resulting width of the column. If not defined, defaults to HORIZONTAL_ALIGN_CENTER. Intended
+ * for testing purposes only.
+ */
+ @Nullable
+ public HorizontalAlignmentProp getHorizontalAlignment() {
+ if (mImpl.hasHorizontalAlignment()) {
+ return HorizontalAlignmentProp.fromProto(mImpl.getHorizontalAlignment());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the width of this column. If not defined, this will size itself to fit all of its
+ * children (i.e. a WrappedDimension). Intended for testing purposes only.
+ */
+ @Nullable
+ public ContainerDimension getWidth() {
+ if (mImpl.hasWidth()) {
+ return DimensionBuilders.containerDimensionFromProto(mImpl.getWidth());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the height of this column. If not defined, this will size itself to fit all of its
+ * children (i.e. a WrappedDimension). Intended for testing purposes only.
+ */
+ @Nullable
+ public ContainerDimension getHeight() {
+ if (mImpl.hasHeight()) {
+ return DimensionBuilders.containerDimensionFromProto(mImpl.getHeight());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public Modifiers getModifiers() {
+ if (mImpl.hasModifiers()) {
+ return Modifiers.fromProto(mImpl.getModifiers());
+ } else {
+ return null;
+ }
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static Column fromProto(@NonNull LayoutElementProto.Column proto) {
+ return new Column(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.Column toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.LayoutElement toLayoutElementProto() {
+ return LayoutElementProto.LayoutElement.newBuilder().setColumn(mImpl).build();
+ }
+
+ /** Builder for {@link Column}. */
+ public static final class Builder implements LayoutElement.Builder {
+ private final LayoutElementProto.Column.Builder mImpl =
+ LayoutElementProto.Column.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1411218529);
+
+ public Builder() {}
+
+ /** Adds one item to the list of child elements to place inside this {@link Column}. */
+ @NonNull
+ public Builder addContent(@NonNull LayoutElement content) {
+ mImpl.addContents(content.toLayoutElementProto());
+ mFingerprint.addChildNode(checkNotNull(content.getFingerprint()));
+ return this;
+ }
+
+ /**
+ * Sets the horizontal alignment of elements inside this column, if they are narrower than the
+ * resulting width of the column. If not defined, defaults to HORIZONTAL_ALIGN_CENTER.
+ */
+ @NonNull
+ public Builder setHorizontalAlignment(@NonNull HorizontalAlignmentProp horizontalAlignment) {
+ mImpl.setHorizontalAlignment(horizontalAlignment.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(horizontalAlignment.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the horizontal alignment of elements inside this column, if they are narrower
+ * than the resulting width of the column. If not defined, defaults to
+ * HORIZONTAL_ALIGN_CENTER.
+ */
+ @NonNull
+ public Builder setHorizontalAlignment(@HorizontalAlignment int horizontalAlignment) {
+ mImpl.setHorizontalAlignment(
+ AlignmentProto.HorizontalAlignmentProp.newBuilder()
+ .setValue(
+ AlignmentProto.HorizontalAlignment.forNumber(
+ horizontalAlignment)));
+ return this;
+ }
+
+ /**
+ * Sets the width of this column. If not defined, this will size itself to fit all of its
+ * children (i.e. a WrappedDimension).
+ */
+ @NonNull
+ public Builder setWidth(@NonNull ContainerDimension width) {
+ mImpl.setWidth(width.toContainerDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(width.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the height of this column. If not defined, this will size itself to fit all of its
+ * children (i.e. a WrappedDimension).
+ */
+ @NonNull
+ public Builder setHeight(@NonNull ContainerDimension height) {
+ mImpl.setHeight(height.toContainerDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(height.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Sets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. */
+ @NonNull
+ public Builder setModifiers(@NonNull Modifiers modifiers) {
+ mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+
+ @Override
+ @NonNull
+ public Column build() {
+ return new Column(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /**
+ * A row of elements. Each child will be laid out horizontally, one after another (i.e. stacking
+ * to the right). This element will size itself to the smallest size required to hold all of its
+ * children (e.g. if it contains three elements sized 10x10, 20x20 and 30x30, the resulting row
+ * will be 60x30).
+ *
+ * <p>If specified, vertical_alignment can be used to control the gravity inside the container,
+ * affecting the vertical placement of children whose width are smaller than the resulting row
+ * height.
+ */
+ public static final class Row implements LayoutElement {
+ private final LayoutElementProto.Row mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ Row(LayoutElementProto.Row impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets the list of child elements to place inside this {@link Row}. Intended for testing
+ * purposes only.
+ */
+ @NonNull
+ public List<LayoutElement> getContents() {
+ List<LayoutElement> list = new ArrayList<>();
+ for (LayoutElementProto.LayoutElement item : mImpl.getContentsList()) {
+ list.add(LayoutElementBuilders.layoutElementFromProto(item));
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ /**
+ * Gets the vertical alignment of elements inside this row, if they are narrower than the
+ * resulting height of the row. If not defined, defaults to VERTICAL_ALIGN_CENTER. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public VerticalAlignmentProp getVerticalAlignment() {
+ if (mImpl.hasVerticalAlignment()) {
+ return VerticalAlignmentProp.fromProto(mImpl.getVerticalAlignment());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the width of this row. If not defined, this will size itself to fit all of its children
+ * (i.e. a WrappedDimension). Intended for testing purposes only.
+ */
+ @Nullable
+ public ContainerDimension getWidth() {
+ if (mImpl.hasWidth()) {
+ return DimensionBuilders.containerDimensionFromProto(mImpl.getWidth());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the height of this row. If not defined, this will size itself to fit all of its children
+ * (i.e. a WrappedDimension). Intended for testing purposes only.
+ */
+ @Nullable
+ public ContainerDimension getHeight() {
+ if (mImpl.hasHeight()) {
+ return DimensionBuilders.containerDimensionFromProto(mImpl.getHeight());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public Modifiers getModifiers() {
+ if (mImpl.hasModifiers()) {
+ return Modifiers.fromProto(mImpl.getModifiers());
+ } else {
+ return null;
+ }
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static Row fromProto(@NonNull LayoutElementProto.Row proto) {
+ return new Row(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.Row toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.LayoutElement toLayoutElementProto() {
+ return LayoutElementProto.LayoutElement.newBuilder().setRow(mImpl).build();
+ }
+
+ /** Builder for {@link Row}. */
+ public static final class Builder implements LayoutElement.Builder {
+ private final LayoutElementProto.Row.Builder mImpl = LayoutElementProto.Row.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1537205448);
+
+ public Builder() {}
+
+ /** Adds one item to the list of child elements to place inside this {@link Row}. */
+ @NonNull
+ public Builder addContent(@NonNull LayoutElement content) {
+ mImpl.addContents(content.toLayoutElementProto());
+ mFingerprint.addChildNode(checkNotNull(content.getFingerprint()));
+ return this;
+ }
+
+ /**
+ * Sets the vertical alignment of elements inside this row, if they are narrower than the
+ * resulting height of the row. If not defined, defaults to VERTICAL_ALIGN_CENTER.
+ */
+ @NonNull
+ public Builder setVerticalAlignment(@NonNull VerticalAlignmentProp verticalAlignment) {
+ mImpl.setVerticalAlignment(verticalAlignment.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(verticalAlignment.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the vertical alignment of elements inside this row, if they are narrower than
+ * the resulting height of the row. If not defined, defaults to VERTICAL_ALIGN_CENTER.
+ */
+ @NonNull
+ public Builder setVerticalAlignment(@VerticalAlignment int verticalAlignment) {
+ mImpl.setVerticalAlignment(
+ AlignmentProto.VerticalAlignmentProp.newBuilder()
+ .setValue(
+ AlignmentProto.VerticalAlignment.forNumber(
+ verticalAlignment)));
+ return this;
+ }
+
+ /**
+ * Sets the width of this row. If not defined, this will size itself to fit all of its
+ * children (i.e. a WrappedDimension).
+ */
+ @NonNull
+ public Builder setWidth(@NonNull ContainerDimension width) {
+ mImpl.setWidth(width.toContainerDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(width.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the height of this row. If not defined, this will size itself to fit all of its
+ * children (i.e. a WrappedDimension).
+ */
+ @NonNull
+ public Builder setHeight(@NonNull ContainerDimension height) {
+ mImpl.setHeight(height.toContainerDimensionProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(height.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Sets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. */
+ @NonNull
+ public Builder setModifiers(@NonNull Modifiers modifiers) {
+ mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+
+ @Override
+ @NonNull
+ public Row build() {
+ return new Row(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /**
+ * An arc container. This container will fill itself to a circle, which fits inside its parent
+ * container, and all of its children will be placed on that circle. The fields anchor_angle and
+ * anchor_type can be used to specify where to draw children within this circle.
+ */
+ public static final class Arc implements LayoutElement {
+ private final LayoutElementProto.Arc mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ Arc(LayoutElementProto.Arc impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets contents of this container. Intended for testing purposes only. */
+ @NonNull
+ public List<ArcLayoutElement> getContents() {
+ List<ArcLayoutElement> list = new ArrayList<>();
+ for (LayoutElementProto.ArcLayoutElement item : mImpl.getContentsList()) {
+ list.add(LayoutElementBuilders.arcLayoutElementFromProto(item));
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ /**
+ * Gets the angle for the anchor, used with anchor_type to determine where to draw children.
+ * Note that 0 degrees is the 12 o clock position on a device, and the angle sweeps clockwise.
+ * If not defined, defaults to 0 degrees.
+ *
+ * <p>Values do not have to be clamped to the range 0-360; values less than 0 degrees will sweep
+ * anti-clockwise (i.e. -90 degrees is equivalent to 270 degrees), and values >360 will be be
+ * placed at X mod 360 degrees. Intended for testing purposes only.
+ */
+ @Nullable
+ public DegreesProp getAnchorAngle() {
+ if (mImpl.hasAnchorAngle()) {
+ return DegreesProp.fromProto(mImpl.getAnchorAngle());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets how to align the contents of this container relative to anchor_angle. If not defined,
+ * defaults to ARC_ANCHOR_CENTER. Intended for testing purposes only.
+ */
+ @Nullable
+ public ArcAnchorTypeProp getAnchorType() {
+ if (mImpl.hasAnchorType()) {
+ return ArcAnchorTypeProp.fromProto(mImpl.getAnchorType());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets vertical alignment of elements within the arc. If the {@link Arc}'s thickness is larger
+ * than the thickness of the element being drawn, this controls whether the element should be
+ * drawn towards the inner or outer edge of the arc, or drawn in the center. If not defined,
+ * defaults to VERTICAL_ALIGN_CENTER. Intended for testing purposes only.
+ */
+ @Nullable
+ public VerticalAlignmentProp getVerticalAlign() {
+ if (mImpl.hasVerticalAlign()) {
+ return VerticalAlignmentProp.fromProto(mImpl.getVerticalAlign());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public Modifiers getModifiers() {
+ if (mImpl.hasModifiers()) {
+ return Modifiers.fromProto(mImpl.getModifiers());
+ } else {
+ return null;
+ }
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static Arc fromProto(@NonNull LayoutElementProto.Arc proto) {
+ return new Arc(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.Arc toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.LayoutElement toLayoutElementProto() {
+ return LayoutElementProto.LayoutElement.newBuilder().setArc(mImpl).build();
+ }
+
+ /** Builder for {@link Arc}. */
+ public static final class Builder implements LayoutElement.Builder {
+ private final LayoutElementProto.Arc.Builder mImpl = LayoutElementProto.Arc.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(299028337);
+
+ public Builder() {}
+
+ /** Adds one item to contents of this container. */
+ @NonNull
+ public Builder addContent(@NonNull ArcLayoutElement content) {
+ mImpl.addContents(content.toArcLayoutElementProto());
+ mFingerprint.addChildNode(checkNotNull(content.getFingerprint()));
+ return this;
+ }
+
+ /**
+ * Sets the angle for the anchor, used with anchor_type to determine where to draw children.
+ * Note that 0 degrees is the 12 o clock position on a device, and the angle sweeps clockwise.
+ * If not defined, defaults to 0 degrees.
+ *
+ * <p>Values do not have to be clamped to the range 0-360; values less than 0 degrees will
+ * sweep anti-clockwise (i.e. -90 degrees is equivalent to 270 degrees), and values >360 will
+ * be be placed at X mod 360 degrees.
+ */
+ @NonNull
+ public Builder setAnchorAngle(@NonNull DegreesProp anchorAngle) {
+ mImpl.setAnchorAngle(anchorAngle.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(anchorAngle.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets how to align the contents of this container relative to anchor_angle. If not defined,
+ * defaults to ARC_ANCHOR_CENTER.
+ */
+ @NonNull
+ public Builder setAnchorType(@NonNull ArcAnchorTypeProp anchorType) {
+ mImpl.setAnchorType(anchorType.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(anchorType.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets how to align the contents of this container relative to anchor_angle. If not
+ * defined, defaults to ARC_ANCHOR_CENTER.
+ */
+ @NonNull
+ public Builder setAnchorType(@ArcAnchorType int anchorType) {
+ mImpl.setAnchorType(
+ AlignmentProto.ArcAnchorTypeProp.newBuilder()
+ .setValue(AlignmentProto.ArcAnchorType.forNumber(anchorType)));
+ return this;
+ }
+
+ /**
+ * Sets vertical alignment of elements within the arc. If the {@link Arc}'s thickness is
+ * larger than the thickness of the element being drawn, this controls whether the element
+ * should be drawn towards the inner or outer edge of the arc, or drawn in the center. If not
+ * defined, defaults to VERTICAL_ALIGN_CENTER.
+ */
+ @NonNull
+ public Builder setVerticalAlign(@NonNull VerticalAlignmentProp verticalAlign) {
+ mImpl.setVerticalAlign(verticalAlign.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(verticalAlign.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+ /**
+ * Sets vertical alignment of elements within the arc. If the {@link Arc}'s thickness is
+ * larger than the thickness of the element being drawn, this controls whether the
+ * element should be drawn towards the inner or outer edge of the arc, or drawn in the
+ * center. If not defined, defaults to VERTICAL_ALIGN_CENTER.
+ */
+ @NonNull
+ public Builder setVerticalAlign(@VerticalAlignment int verticalAlign) {
+ mImpl.setVerticalAlign(
+ AlignmentProto.VerticalAlignmentProp.newBuilder()
+ .setValue(
+ AlignmentProto.VerticalAlignment.forNumber(
+ verticalAlign)));
+ return this;
+ }
+
+ /** Sets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. */
+ @NonNull
+ public Builder setModifiers(@NonNull Modifiers modifiers) {
+ mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+
+ @Override
+ @NonNull
+ public Arc build() {
+ return new Arc(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A text element that can be used in an {@link Arc}. */
+ public static final class ArcText implements ArcLayoutElement {
+ private final LayoutElementProto.ArcText mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ ArcText(LayoutElementProto.ArcText impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the text to render. Intended for testing purposes only. */
+ @Nullable
+ public StringProp getText() {
+ if (mImpl.hasText()) {
+ return StringProp.fromProto(mImpl.getText());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the style of font to use (size, bold etc). If not specified, defaults to the platform's
+ * default body font. Intended for testing purposes only.
+ */
+ @Nullable
+ public FontStyle getFontStyle() {
+ if (mImpl.hasFontStyle()) {
+ return FontStyle.fromProto(mImpl.getFontStyle());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public ArcModifiers getModifiers() {
+ if (mImpl.hasModifiers()) {
+ return ArcModifiers.fromProto(mImpl.getModifiers());
+ } else {
+ return null;
+ }
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static ArcText fromProto(@NonNull LayoutElementProto.ArcText proto) {
+ return new ArcText(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.ArcText toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.ArcLayoutElement toArcLayoutElementProto() {
+ return LayoutElementProto.ArcLayoutElement.newBuilder().setText(mImpl).build();
+ }
+
+ /** Builder for {@link ArcText}. */
+ public static final class Builder implements ArcLayoutElement.Builder {
+ private final LayoutElementProto.ArcText.Builder mImpl =
+ LayoutElementProto.ArcText.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(434391973);
+
+ public Builder() {}
+
+ /**
+ * Sets the text to render.
+ */
+ @NonNull
+ public Builder setText(@NonNull StringProp text) {
+ mImpl.setText(text.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(text.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Sets the text to render. */
+ @NonNull
+ public Builder setText(@NonNull String text) {
+ mImpl.setText(TypesProto.StringProp.newBuilder().setValue(text));
+ return this;
+ }
+
+ /**
+ * Sets the style of font to use (size, bold etc). If not specified, defaults to the
+ * platform's default body font.
+ */
+ @NonNull
+ public Builder setFontStyle(@NonNull FontStyle fontStyle) {
+ mImpl.setFontStyle(fontStyle.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(fontStyle.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Sets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. */
+ @NonNull
+ public Builder setModifiers(@NonNull ArcModifiers modifiers) {
+ mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+
+ @Override
+ @NonNull
+ public ArcText build() {
+ return new ArcText(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A line that can be used in an {@link Arc} and renders as a round progress bar. */
+ public static final class ArcLine implements ArcLayoutElement {
+ private final LayoutElementProto.ArcLine mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ ArcLine(LayoutElementProto.ArcLine impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets the length of this line, in degrees. If not defined, defaults to 0. Intended for testing
+ * purposes only.
+ */
+ @Nullable
+ public DegreesProp getLength() {
+ if (mImpl.hasLength()) {
+ return DegreesProp.fromProto(mImpl.getLength());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the thickness of this line. If not defined, defaults to 0. Intended for testing purposes
+ * only.
+ */
+ @Nullable
+ public DpProp getThickness() {
+ if (mImpl.hasThickness()) {
+ return DpProp.fromProto(mImpl.getThickness());
+ } else {
+ return null;
+ }
+ }
+
+ /** Gets the color of this line. Intended for testing purposes only. */
+ @Nullable
+ public ColorProp getColor() {
+ if (mImpl.hasColor()) {
+ return ColorProp.fromProto(mImpl.getColor());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public ArcModifiers getModifiers() {
+ if (mImpl.hasModifiers()) {
+ return ArcModifiers.fromProto(mImpl.getModifiers());
+ } else {
+ return null;
+ }
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static ArcLine fromProto(@NonNull LayoutElementProto.ArcLine proto) {
+ return new ArcLine(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.ArcLine toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.ArcLayoutElement toArcLayoutElementProto() {
+ return LayoutElementProto.ArcLayoutElement.newBuilder().setLine(mImpl).build();
+ }
+
+ /** Builder for {@link ArcLine}. */
+ public static final class Builder implements ArcLayoutElement.Builder {
+ private final LayoutElementProto.ArcLine.Builder mImpl =
+ LayoutElementProto.ArcLine.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1371793535);
+
+ public Builder() {}
+
+ /**
+ * Sets the length of this line, in degrees. If not defined, defaults to 0.
+ */
+ @NonNull
+ public Builder setLength(@NonNull DegreesProp length) {
+ mImpl.setLength(length.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(length.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the thickness of this line. If not defined, defaults to 0.
+ */
+ @NonNull
+ public Builder setThickness(@NonNull DpProp thickness) {
+ mImpl.setThickness(thickness.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(thickness.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the color of this line.
+ */
+ @NonNull
+ public Builder setColor(@NonNull ColorProp color) {
+ mImpl.setColor(color.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(color.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Sets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. */
+ @NonNull
+ public Builder setModifiers(@NonNull ArcModifiers modifiers) {
+ mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+
+ @Override
+ @NonNull
+ public ArcLine build() {
+ return new ArcLine(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A simple spacer used to provide padding between adjacent elements in an {@link Arc}. */
+ public static final class ArcSpacer implements ArcLayoutElement {
+ private final LayoutElementProto.ArcSpacer mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ ArcSpacer(LayoutElementProto.ArcSpacer impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets the length of this spacer, in degrees. If not defined, defaults to 0. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public DegreesProp getLength() {
+ if (mImpl.hasLength()) {
+ return DegreesProp.fromProto(mImpl.getLength());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the thickness of this spacer, in DP. If not defined, defaults to 0. Intended for testing
+ * purposes only.
+ */
+ @Nullable
+ public DpProp getThickness() {
+ if (mImpl.hasThickness()) {
+ return DpProp.fromProto(mImpl.getThickness());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public ArcModifiers getModifiers() {
+ if (mImpl.hasModifiers()) {
+ return ArcModifiers.fromProto(mImpl.getModifiers());
+ } else {
+ return null;
+ }
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static ArcSpacer fromProto(@NonNull LayoutElementProto.ArcSpacer proto) {
+ return new ArcSpacer(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.ArcSpacer toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.ArcLayoutElement toArcLayoutElementProto() {
+ return LayoutElementProto.ArcLayoutElement.newBuilder().setSpacer(mImpl).build();
+ }
+
+ /** Builder for {@link ArcSpacer}. */
+ public static final class Builder implements ArcLayoutElement.Builder {
+ private final LayoutElementProto.ArcSpacer.Builder mImpl =
+ LayoutElementProto.ArcSpacer.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-179760535);
+
+ public Builder() {}
+
+ /**
+ * Sets the length of this spacer, in degrees. If not defined, defaults to 0.
+ */
+ @NonNull
+ public Builder setLength(@NonNull DegreesProp length) {
+ mImpl.setLength(length.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(length.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the thickness of this spacer, in DP. If not defined, defaults to 0.
+ */
+ @NonNull
+ public Builder setThickness(@NonNull DpProp thickness) {
+ mImpl.setThickness(thickness.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(thickness.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Sets {@link androidx.wear.tiles.ModifiersBuilders.Modifiers} for this element. */
+ @NonNull
+ public Builder setModifiers(@NonNull ArcModifiers modifiers) {
+ mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public ArcSpacer build() {
+ return new ArcSpacer(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A container that allows a standard {@link LayoutElement} to be added to an {@link Arc}. */
+ public static final class ArcAdapter implements ArcLayoutElement {
+ private final LayoutElementProto.ArcAdapter mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ ArcAdapter(LayoutElementProto.ArcAdapter impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the element to adapt to an {@link Arc}. Intended for testing purposes only. */
+ @Nullable
+ public LayoutElement getContent() {
+ if (mImpl.hasContent()) {
+ return LayoutElementBuilders.layoutElementFromProto(mImpl.getContent());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets whether this adapter's contents should be rotated, according to its position in the arc
+ * or not. As an example, assume that an {@link Image} has been added to the arc, and ends up at
+ * the 3 o clock position. If rotate_contents = true, the image will be placed at the 3 o clock
+ * position, and will be rotated clockwise through 90 degrees. If rotate_contents = false, the
+ * image will be placed at the 3 o clock position, but itself will not be rotated. If not
+ * defined, defaults to false. Intended for testing purposes only.
+ */
+ @Nullable
+ public BoolProp getRotateContents() {
+ if (mImpl.hasRotateContents()) {
+ return BoolProp.fromProto(mImpl.getRotateContents());
+ } else {
+ return null;
+ }
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static ArcAdapter fromProto(@NonNull LayoutElementProto.ArcAdapter proto) {
+ return new ArcAdapter(proto, null);
+ }
+
+ @NonNull
+ LayoutElementProto.ArcAdapter toProto() {
+ return mImpl;
+ }
+
+ /** @hide */
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.ArcLayoutElement toArcLayoutElementProto() {
+ return LayoutElementProto.ArcLayoutElement.newBuilder().setAdapter(mImpl).build();
+ }
+
+ /** Builder for {@link ArcAdapter}. */
+ public static final class Builder implements ArcLayoutElement.Builder {
+ private final LayoutElementProto.ArcAdapter.Builder mImpl =
+ LayoutElementProto.ArcAdapter.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1696473935);
+
+ public Builder() {}
+
+ /** Sets the element to adapt to an {@link Arc}. */
+ @NonNull
+ public Builder setContent(@NonNull LayoutElement content) {
+ mImpl.setContent(content.toLayoutElementProto());
+ mFingerprint.addChildNode(checkNotNull(content.getFingerprint()));
+ return this;
+ }
+
+ /**
+ * Sets whether this adapter's contents should be rotated, according to its position in the
+ * arc or not. As an example, assume that an {@link Image} has been added to the arc, and ends
+ * up at the 3 o clock position. If rotate_contents = true, the image will be placed at the 3
+ * o clock position, and will be rotated clockwise through 90 degrees. If rotate_contents =
+ * false, the image will be placed at the 3 o clock position, but itself will not be rotated.
+ * If not defined, defaults to false.
+ */
+ @NonNull
+ public Builder setRotateContents(@NonNull BoolProp rotateContents) {
+ mImpl.setRotateContents(rotateContents.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(rotateContents.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets whether this adapter's contents should be rotated, according to its position in
+ * the arc or not. As an example, assume that an {@link Image} has been added to the
+ * arc, and ends up at the 3 o clock position. If rotate_contents = true, the image will
+ * be placed at the 3 o clock position, and will be rotated clockwise through 90
+ * degrees. If rotate_contents = false, the image will be placed at the 3 o clock
+ * position, but itself will not be rotated. If not defined, defaults to false.
+ */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @NonNull
+ public Builder setRotateContents(boolean rotateContents) {
+ mImpl.setRotateContents(TypesProto.BoolProp.newBuilder().setValue(rotateContents));
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public ArcAdapter build() {
+ return new ArcAdapter(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /**
+ * Interface defining the root of all layout elements. This exists to act as a holder for all of
+ * the actual layout elements above.
+ */
+ public interface LayoutElement {
+ /**
+ * Get the protocol buffer representation of this object.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ LayoutElementProto.LayoutElement toLayoutElementProto();
+
+ /**
+ * Get the fingerprint for this object or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ Fingerprint getFingerprint();
+
+ /** Builder to create {@link LayoutElement} objects. */
+ @SuppressLint("StaticFinalBuilder")
+ interface Builder {
+
+ /** Builds an instance with values accumulated in this Builder. */
+ @NonNull
+ LayoutElement build();
+ }
+ }
+
+ @NonNull
+ static LayoutElement layoutElementFromProto(@NonNull LayoutElementProto.LayoutElement proto) {
+ if (proto.hasColumn()) {
+ return Column.fromProto(proto.getColumn());
+ }
+ if (proto.hasRow()) {
+ return Row.fromProto(proto.getRow());
+ }
+ if (proto.hasBox()) {
+ return Box.fromProto(proto.getBox());
+ }
+ if (proto.hasSpacer()) {
+ return Spacer.fromProto(proto.getSpacer());
+ }
+ if (proto.hasText()) {
+ return Text.fromProto(proto.getText());
+ }
+ if (proto.hasImage()) {
+ return Image.fromProto(proto.getImage());
+ }
+ if (proto.hasArc()) {
+ return Arc.fromProto(proto.getArc());
+ }
+ if (proto.hasSpannable()) {
+ return Spannable.fromProto(proto.getSpannable());
+ }
+ throw new IllegalStateException("Proto was not a recognised instance of LayoutElement");
+ }
+
+ /**
+ * Interface defining the root of all elements that can be used in an {@link Arc}. This exists to
+ * act as a holder for all of the actual arc layout elements above.
+ */
+ public interface ArcLayoutElement {
+ /**
+ * Get the protocol buffer representation of this object.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ LayoutElementProto.ArcLayoutElement toArcLayoutElementProto();
+
+ /**
+ * Get the fingerprint for this object or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ Fingerprint getFingerprint();
+
+ /** Builder to create {@link ArcLayoutElement} objects. */
+ @SuppressLint("StaticFinalBuilder")
+ interface Builder {
+
+ /** Builds an instance with values accumulated in this Builder. */
+ @NonNull
+ ArcLayoutElement build();
+ }
+ }
+
+ @NonNull
+ static ArcLayoutElement arcLayoutElementFromProto(
+ @NonNull LayoutElementProto.ArcLayoutElement proto) {
+ if (proto.hasText()) {
+ return ArcText.fromProto(proto.getText());
+ }
+ if (proto.hasLine()) {
+ return ArcLine.fromProto(proto.getLine());
+ }
+ if (proto.hasSpacer()) {
+ return ArcSpacer.fromProto(proto.getSpacer());
+ }
+ if (proto.hasAdapter()) {
+ return ArcAdapter.fromProto(proto.getAdapter());
+ }
+ throw new IllegalStateException("Proto was not a recognised instance of ArcLayoutElement");
+ }
+
+ /** A complete layout. */
+ public static final class Layout {
+ private final LayoutElementProto.Layout mImpl;
+
+ private Layout(LayoutElementProto.Layout impl) {
+ this.mImpl = impl;
+ }
+
+ /** Gets the root element in the layout. Intended for testing purposes only. */
+ @Nullable
+ public LayoutElement getRoot() {
+ if (mImpl.hasRoot()) {
+ return LayoutElementBuilders.layoutElementFromProto(mImpl.getRoot());
+ } else {
+ return null;
+ }
+ }
+
+ /** Creates a {@link Layout} object containing the given layout element. */
+ @NonNull
+ public static Layout fromLayoutElement(@NonNull LayoutElement layoutElement) {
+ return new Builder().setRoot(layoutElement).build();
+ }
+
+ /** Converts to byte array representation. */
+ @NonNull
+ @ProtoLayoutExperimental
+ public byte[] toByteArray() {
+ return mImpl.toByteArray();
+ }
+
+ /** Converts from byte array representation. */
+ @SuppressWarnings("ProtoParseWithRegistry")
+ @Nullable
+ @ProtoLayoutExperimental
+ public static Layout fromByteArray(@NonNull byte[] byteArray) {
+ try {
+ return fromProto(LayoutElementProto.Layout.parseFrom(byteArray));
+ } catch (InvalidProtocolBufferException e) {
+ return null;
+ }
+ }
+
+ @NonNull
+ static Layout fromProto(@NonNull LayoutElementProto.Layout proto) {
+ return new Layout(proto);
+ }
+
+ /**
+ * Returns the internal proto instance.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.Layout toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link Layout} */
+ public static final class Builder {
+ private final LayoutElementProto.Layout.Builder mImpl =
+ LayoutElementProto.Layout.newBuilder();
+
+ public Builder() {}
+
+ /** Sets the root element in the layout. */
+ @NonNull
+ public Builder setRoot(@NonNull LayoutElement root) {
+ mImpl.setRoot(root.toLayoutElementProto());
+ @Nullable Fingerprint fingerprint = root.getFingerprint();
+ if (fingerprint != null) {
+ mImpl.setFingerprint(
+ TreeFingerprint.newBuilder().setRoot(fingerprintToProto(fingerprint)));
+ }
+ return this;
+ }
+
+ private static FingerprintProto.NodeFingerprint fingerprintToProto(Fingerprint fingerprint) {
+ FingerprintProto.NodeFingerprint.Builder builder =
+ FingerprintProto.NodeFingerprint.newBuilder();
+ if (fingerprint.selfTypeValue() != 0) {
+ builder.setSelfTypeValue(fingerprint.selfTypeValue());
+ }
+ if (fingerprint.selfPropsValue() != 0) {
+ builder.setSelfPropsValue(fingerprint.selfPropsValue());
+ }
+ if (fingerprint.childNodesValue() != 0) {
+ builder.setChildNodesValue(fingerprint.childNodesValue());
+ }
+ for (Fingerprint childNode : fingerprint.childNodes()) {
+ builder.addChildNodes(fingerprintToProto(childNode));
+ }
+ return builder.build();
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public Layout build() {
+ return Layout.fromProto(mImpl.build());
+ }
+ }
+ }
+
+ /**
+ * The horizontal alignment of an element within its container.
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @IntDef({
+ HORIZONTAL_ALIGN_UNDEFINED,
+ HORIZONTAL_ALIGN_LEFT,
+ HORIZONTAL_ALIGN_CENTER,
+ HORIZONTAL_ALIGN_RIGHT,
+ HORIZONTAL_ALIGN_START,
+ HORIZONTAL_ALIGN_END
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface HorizontalAlignment {}
+
+ /** Horizontal alignment is undefined. */
+ public static final int HORIZONTAL_ALIGN_UNDEFINED = 0;
+
+ /** Horizontally align to the left. */
+ public static final int HORIZONTAL_ALIGN_LEFT = 1;
+
+ /** Horizontally align to center. */
+ public static final int HORIZONTAL_ALIGN_CENTER = 2;
+
+ /** Horizontally align to the right. */
+ public static final int HORIZONTAL_ALIGN_RIGHT = 3;
+
+ /** Horizontally align to the content start (left in LTR layouts, right in RTL layouts). */
+ public static final int HORIZONTAL_ALIGN_START = 4;
+
+ /** Horizontally align to the content end (right in LTR layouts, left in RTL layouts). */
+ public static final int HORIZONTAL_ALIGN_END = 5;
+
+ /**
+ * The vertical alignment of an element within its container.
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @IntDef({
+ VERTICAL_ALIGN_UNDEFINED,
+ VERTICAL_ALIGN_TOP,
+ VERTICAL_ALIGN_CENTER,
+ VERTICAL_ALIGN_BOTTOM
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface VerticalAlignment {}
+
+ /** Vertical alignment is undefined. */
+ public static final int VERTICAL_ALIGN_UNDEFINED = 0;
+
+ /** Vertically align to the top. */
+ public static final int VERTICAL_ALIGN_TOP = 1;
+
+ /** Vertically align to center. */
+ public static final int VERTICAL_ALIGN_CENTER = 2;
+
+ /** Vertically align to the bottom. */
+ public static final int VERTICAL_ALIGN_BOTTOM = 3;
+
+ /**
+ * Alignment of a text element.
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @IntDef({TEXT_ALIGN_UNDEFINED, TEXT_ALIGN_START, TEXT_ALIGN_CENTER, TEXT_ALIGN_END})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TextAlignment {}
+
+ /** Alignment is undefined. */
+ public static final int TEXT_ALIGN_UNDEFINED = 0;
+
+ /**
+ * Align to the "start" of the {@link androidx.wear.tiles.LayoutElementBuilders.Text} element
+ * (left in LTR layouts, right in RTL layouts).
+ */
+ public static final int TEXT_ALIGN_START = 1;
+
+ /** Align to the center of the {@link androidx.wear.tiles.LayoutElementBuilders.Text} element. */
+ public static final int TEXT_ALIGN_CENTER = 2;
+
+ /**
+ * Align to the "end" of the {@link androidx.wear.tiles.LayoutElementBuilders.Text} element (right
+ * in LTR layouts, left in RTL layouts).
+ */
+ public static final int TEXT_ALIGN_END = 3;
+
+ /**
+ * The anchor position of an {@link androidx.wear.tiles.LayoutElementBuilders.Arc}'s elements.
+ * This is used to specify how elements added to an {@link
+ * androidx.wear.tiles.LayoutElementBuilders.Arc} should be laid out with respect to anchor_angle.
+ *
+ * <p>As an example, assume that the following diagrams are wrapped to an arc, and each represents
+ * an {@link androidx.wear.tiles.LayoutElementBuilders.Arc} element containing a single {@link
+ * androidx.wear.tiles.LayoutElementBuilders.Text} element. The {@link
+ * androidx.wear.tiles.LayoutElementBuilders.Text} element's anchor_angle is "0" for all cases.
+ *
+ * <pre>{@code
+ * ARC_ANCHOR_START:
+ * -180 0 180
+ * Hello World!
+ *
+ *
+ * ARC_ANCHOR_CENTER:
+ * -180 0 180
+ * Hello World!
+ *
+ * ARC_ANCHOR_END:
+ * -180 0 180
+ * Hello World!
+ *
+ * }</pre>
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @IntDef({ARC_ANCHOR_UNDEFINED, ARC_ANCHOR_START, ARC_ANCHOR_CENTER, ARC_ANCHOR_END})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ArcAnchorType {}
+
+ /** Anchor position is undefined. */
+ public static final int ARC_ANCHOR_UNDEFINED = 0;
+
+ /**
+ * Anchor at the start of the elements. This will cause elements added to an arc to begin at the
+ * given anchor_angle, and sweep around to the right.
+ */
+ public static final int ARC_ANCHOR_START = 1;
+
+ /**
+ * Anchor at the center of the elements. This will cause the center of the whole set of elements
+ * added to an arc to be pinned at the given anchor_angle.
+ */
+ public static final int ARC_ANCHOR_CENTER = 2;
+
+ /**
+ * Anchor at the end of the elements. This will cause the set of elements inside the arc to end at
+ * the specified anchor_angle, i.e. all elements should be to the left of anchor_angle.
+ */
+ public static final int ARC_ANCHOR_END = 3;
+
+ /** An extensible {@code HorizontalAlignment} property. */
+ public static final class HorizontalAlignmentProp {
+ private final AlignmentProto.HorizontalAlignmentProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ HorizontalAlignmentProp(
+ AlignmentProto.HorizontalAlignmentProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value. Intended for testing purposes only. */
+ @HorizontalAlignment
+ public int getValue() {
+ return mImpl.getValue().getNumber();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static HorizontalAlignmentProp fromProto(
+ @NonNull AlignmentProto.HorizontalAlignmentProp proto) {
+ return new HorizontalAlignmentProp(proto, null);
+ }
+
+ @NonNull
+ AlignmentProto.HorizontalAlignmentProp toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link HorizontalAlignmentProp} */
+ public static final class Builder {
+ private final AlignmentProto.HorizontalAlignmentProp.Builder mImpl =
+ AlignmentProto.HorizontalAlignmentProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-384830516);
+
+ public Builder() {}
+
+ /** Sets the value. */
+ @NonNull
+ public Builder setValue(@HorizontalAlignment int value) {
+ mImpl.setValue(AlignmentProto.HorizontalAlignment.forNumber(value));
+ mFingerprint.recordPropertyUpdate(1, value);
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public HorizontalAlignmentProp build() {
+ return new HorizontalAlignmentProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** An extensible {@code VerticalAlignment} property. */
+ public static final class VerticalAlignmentProp {
+ private final AlignmentProto.VerticalAlignmentProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ VerticalAlignmentProp(
+ AlignmentProto.VerticalAlignmentProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value. Intended for testing purposes only. */
+ @VerticalAlignment
+ public int getValue() {
+ return mImpl.getValue().getNumber();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static VerticalAlignmentProp fromProto(@NonNull AlignmentProto.VerticalAlignmentProp proto) {
+ return new VerticalAlignmentProp(proto, null);
+ }
+
+ @NonNull
+ AlignmentProto.VerticalAlignmentProp toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link VerticalAlignmentProp} */
+ public static final class Builder {
+ private final AlignmentProto.VerticalAlignmentProp.Builder mImpl =
+ AlignmentProto.VerticalAlignmentProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1443510393);
+
+ public Builder() {}
+
+ /** Sets the value. */
+ @NonNull
+ public Builder setValue(@VerticalAlignment int value) {
+ mImpl.setValue(AlignmentProto.VerticalAlignment.forNumber(value));
+ mFingerprint.recordPropertyUpdate(1, value);
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public VerticalAlignmentProp build() {
+ return new VerticalAlignmentProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** An extensible {@code TextAlignment} property. */
+ public static final class TextAlignmentProp {
+ private final AlignmentProto.TextAlignmentProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ TextAlignmentProp(
+ AlignmentProto.TextAlignmentProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value. Intended for testing purposes only. */
+ @TextAlignment
+ public int getValue() {
+ return mImpl.getValue().getNumber();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static TextAlignmentProp fromProto(@NonNull AlignmentProto.TextAlignmentProp proto) {
+ return new TextAlignmentProp(proto, null);
+ }
+
+ @NonNull
+ AlignmentProto.TextAlignmentProp toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link TextAlignmentProp} */
+ public static final class Builder {
+ private final AlignmentProto.TextAlignmentProp.Builder mImpl =
+ AlignmentProto.TextAlignmentProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(797507251);
+
+ public Builder() {}
+
+ /** Sets the value. */
+ @NonNull
+ public Builder setValue(@TextAlignment int value) {
+ mImpl.setValue(AlignmentProto.TextAlignment.forNumber(value));
+ mFingerprint.recordPropertyUpdate(1, value);
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public TextAlignmentProp build() {
+ return new TextAlignmentProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** An extensible {@code ArcAnchorType} property. */
+ public static final class ArcAnchorTypeProp {
+ private final AlignmentProto.ArcAnchorTypeProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ ArcAnchorTypeProp(
+ AlignmentProto.ArcAnchorTypeProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value. Intended for testing purposes only. */
+ @ArcAnchorType
+ public int getValue() {
+ return mImpl.getValue().getNumber();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static ArcAnchorTypeProp fromProto(@NonNull AlignmentProto.ArcAnchorTypeProp proto) {
+ return new ArcAnchorTypeProp(proto, null);
+ }
+
+ @NonNull
+ AlignmentProto.ArcAnchorTypeProp toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link ArcAnchorTypeProp} */
+ public static final class Builder {
+ private final AlignmentProto.ArcAnchorTypeProp.Builder mImpl =
+ AlignmentProto.ArcAnchorTypeProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1193249074);
+
+ public Builder() {}
+
+ /** Sets the value. */
+ @NonNull
+ public Builder setValue(@ArcAnchorType int value) {
+ mImpl.setValue(AlignmentProto.ArcAnchorType.forNumber(value));
+ mFingerprint.recordPropertyUpdate(1, value);
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public ArcAnchorTypeProp build() {
+ return new ArcAnchorTypeProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** Font styles, currently set up to match Wear's font styling. */
+ public static class FontStyles {
+ private static final int LARGE_SCREEN_WIDTH_DP = 210;
+
+ private FontStyles() {
+ }
+
+ private static boolean isLargeScreen(@NonNull DeviceParameters deviceParameters) {
+ return deviceParameters.getScreenWidthDp() >= LARGE_SCREEN_WIDTH_DP;
+ }
+
+ /** Font style for large display text. */
+ @NonNull
+ public static FontStyle.Builder display1(@NonNull DeviceParameters deviceParameters) {
+ return new FontStyle.Builder()
+ .setWeight(FONT_WEIGHT_BOLD)
+ .setSize(DimensionBuilders.sp(isLargeScreen(deviceParameters) ? 54 : 50));
+ }
+
+ /** Font style for medium display text. */
+ @NonNull
+ public static FontStyle.Builder display2(@NonNull DeviceParameters deviceParameters) {
+ return new FontStyle.Builder()
+ .setWeight(FONT_WEIGHT_BOLD)
+ .setSize(DimensionBuilders.sp(isLargeScreen(deviceParameters) ? 44 : 40));
+ }
+
+ /** Font style for small display text. */
+ @NonNull
+ public static FontStyle.Builder display3(@NonNull DeviceParameters deviceParameters) {
+ return new FontStyle.Builder()
+ .setWeight(FONT_WEIGHT_BOLD)
+ .setSize(DimensionBuilders.sp(isLargeScreen(deviceParameters) ? 34 : 30));
+ }
+
+ /** Font style for large title text. */
+ @NonNull
+ public static FontStyle.Builder title1(@NonNull DeviceParameters deviceParameters) {
+ return new FontStyle.Builder()
+ .setWeight(FONT_WEIGHT_BOLD)
+ .setSize(DimensionBuilders.sp(isLargeScreen(deviceParameters) ? 26 : 24));
+ }
+
+ /** Font style for medium title text. */
+ @NonNull
+ public static FontStyle.Builder title2(@NonNull DeviceParameters deviceParameters) {
+ return new FontStyle.Builder()
+ .setWeight(FONT_WEIGHT_BOLD)
+ .setSize(DimensionBuilders.sp(isLargeScreen(deviceParameters) ? 22 : 20));
+ }
+
+ /** Font style for small title text. */
+ @NonNull
+ public static FontStyle.Builder title3(@NonNull DeviceParameters deviceParameters) {
+ return new FontStyle.Builder()
+ .setWeight(FONT_WEIGHT_BOLD)
+ .setSize(DimensionBuilders.sp(isLargeScreen(deviceParameters) ? 18 : 16));
+ }
+
+ /** Font style for large body text. */
+ @NonNull
+ public static FontStyle.Builder body1(@NonNull DeviceParameters deviceParameters) {
+ return new FontStyle.Builder()
+ .setSize(DimensionBuilders.sp(isLargeScreen(deviceParameters) ? 18 : 16));
+ }
+
+ /** Font style for medium body text. */
+ @NonNull
+ public static FontStyle.Builder body2(@NonNull DeviceParameters deviceParameters) {
+ return new FontStyle.Builder()
+ .setSize(DimensionBuilders.sp(isLargeScreen(deviceParameters) ? 16 : 14));
+ }
+
+ /** Font style for button text. */
+ @NonNull
+ public static FontStyle.Builder button(@NonNull DeviceParameters deviceParameters) {
+ return new FontStyle.Builder()
+ .setWeight(FONT_WEIGHT_BOLD)
+ .setSize(DimensionBuilders.sp(isLargeScreen(deviceParameters) ? 16 : 14));
+ }
+
+ /** Font style for large caption text. */
+ @NonNull
+ public static FontStyle.Builder caption1(@NonNull DeviceParameters deviceParameters) {
+ return new FontStyle.Builder()
+ .setSize(DimensionBuilders.sp(isLargeScreen(deviceParameters) ? 16 : 14));
+ }
+
+ /** Font style for medium caption text. */
+ @NonNull
+ public static FontStyle.Builder caption2(@NonNull DeviceParameters deviceParameters) {
+ return new FontStyle.Builder()
+ .setSize(DimensionBuilders.sp(isLargeScreen(deviceParameters) ? 14 : 12));
+ }
+ }
+
+}
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java
new file mode 100644
index 0000000..cc326a4
--- /dev/null
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java
@@ -0,0 +1,1117 @@
+/*
+ * Copyright 2021-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.
+ */
+
+package androidx.wear.protolayout;
+
+import static androidx.annotation.Dimension.DP;
+import static androidx.wear.protolayout.expression.Preconditions.checkNotNull;
+
+import android.annotation.SuppressLint;
+import androidx.annotation.ColorInt;
+import androidx.annotation.Dimension;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.DynamicBuilders;
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicString;
+import androidx.wear.protolayout.expression.Fingerprint;
+import androidx.wear.protolayout.proto.ColorProto;
+import androidx.wear.protolayout.proto.DimensionProto;
+import androidx.wear.protolayout.proto.ModifiersProto;
+import androidx.wear.protolayout.proto.TypesProto;
+import androidx.wear.protolayout.ActionBuilders.Action;
+import androidx.wear.protolayout.ColorBuilders.ColorProp;
+import androidx.wear.protolayout.DimensionBuilders.DpProp;
+import androidx.wear.protolayout.TypeBuilders.BoolProp;
+import androidx.wear.protolayout.protobuf.ByteString;
+import java.util.Arrays;
+
+/** Builders for modifiers for composable layout elements. */
+public final class ModifiersBuilders {
+ private ModifiersBuilders() {}
+
+ /**
+ * A modifier for an element which can have associated Actions for click events. When an element
+ * with a ClickableModifier is clicked it will fire the associated action.
+ */
+ public static final class Clickable {
+ private final ModifiersProto.Clickable mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ Clickable(ModifiersProto.Clickable impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the ID associated with this action. Intended for testing purposes only. */
+ @NonNull
+ public String getId() {
+ return mImpl.getId();
+ }
+
+ /**
+ * Gets the action to perform when the element this modifier is attached to is clicked. Intended
+ * for testing purposes only.
+ */
+ @Nullable
+ public Action getOnClick() {
+ if (mImpl.hasOnClick()) {
+ return ActionBuilders.actionFromProto(mImpl.getOnClick());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static Clickable fromProto(@NonNull ModifiersProto.Clickable proto) {
+ return new Clickable(proto, null);
+ }
+
+ /**
+ * Returns the internal proto instance.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public ModifiersProto.Clickable toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link Clickable} */
+ public static final class Builder {
+ private final ModifiersProto.Clickable.Builder mImpl = ModifiersProto.Clickable.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(595587995);
+
+ public Builder() {}
+
+ /** Sets the ID associated with this action. */
+ @NonNull
+ public Builder setId(@NonNull String id) {
+ mImpl.setId(id);
+ mFingerprint.recordPropertyUpdate(1, id.hashCode());
+ return this;
+ }
+
+ /** Sets the action to perform when the element this modifier is attached to is clicked. */
+ @NonNull
+ public Builder setOnClick(@NonNull Action onClick) {
+ mImpl.setOnClick(onClick.toActionProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(onClick.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public Clickable build() {
+ return new Clickable(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /**
+ * A modifier for an element which has accessibility semantics associated with it. This should
+ * generally be used sparingly, and in most cases should only be applied to the top-level layout
+ * element or to Clickables.
+ */
+ public static final class Semantics {
+ private final ModifiersProto.Semantics mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ Semantics(ModifiersProto.Semantics impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets the content description associated with this element. This will be dictated when the
+ * element is focused by the screen reader. Intended for testing purposes only.
+ */
+ @NonNull
+ public String getContentDescription() {
+ if (mImpl.hasContentDescription()) {
+ return mImpl.getContentDescription().getValue();
+ }
+ return mImpl.getObsoleteContentDescription();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static Semantics fromProto(@NonNull ModifiersProto.Semantics proto) {
+ return new Semantics(proto, null);
+ }
+
+ @NonNull
+ ModifiersProto.Semantics toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link Semantics} */
+ public static final class Builder {
+ private final ModifiersProto.Semantics.Builder mImpl = ModifiersProto.Semantics.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1479823155);
+
+ public Builder() {}
+
+ /**
+ * Sets the content description associated with this element. This will be dictated when the
+ * element is focused by the screen reader.
+ */
+ @NonNull
+ public Builder setContentDescription(@NonNull String contentDescription) {
+ mImpl.setObsoleteContentDescription(contentDescription);
+ mImpl.mergeContentDescription(
+ TypesProto.StringProp.newBuilder().setValue(contentDescription).build());
+ mFingerprint.recordPropertyUpdate(4, contentDescription.hashCode());
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public Semantics build() {
+ return new Semantics(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A modifier to apply padding around an element. */
+ public static final class Padding {
+ private final ModifiersProto.Padding mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ Padding(ModifiersProto.Padding impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets the padding on the end of the content, depending on the layout direction, in DP and the
+ * value of "rtl_aware". Intended for testing purposes only.
+ */
+ @Nullable
+ public DpProp getEnd() {
+ if (mImpl.hasEnd()) {
+ return DpProp.fromProto(mImpl.getEnd());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the padding on the start of the content, depending on the layout direction, in DP and
+ * the value of "rtl_aware". Intended for testing purposes only.
+ */
+ @Nullable
+ public DpProp getStart() {
+ if (mImpl.hasStart()) {
+ return DpProp.fromProto(mImpl.getStart());
+ } else {
+ return null;
+ }
+ }
+
+ /** Gets the padding at the top, in DP. Intended for testing purposes only. */
+ @Nullable
+ public DpProp getTop() {
+ if (mImpl.hasTop()) {
+ return DpProp.fromProto(mImpl.getTop());
+ } else {
+ return null;
+ }
+ }
+
+ /** Gets the padding at the bottom, in DP. Intended for testing purposes only. */
+ @Nullable
+ public DpProp getBottom() {
+ if (mImpl.hasBottom()) {
+ return DpProp.fromProto(mImpl.getBottom());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets whether the start/end padding is aware of RTL support. If true, the values for start/end
+ * will follow the layout direction (i.e. start will refer to the right hand side of the
+ * container if the device is using an RTL locale). If false, start/end will always map to
+ * left/right, accordingly. Intended for testing purposes only.
+ */
+ @Nullable
+ public BoolProp getRtlAware() {
+ if (mImpl.hasRtlAware()) {
+ return BoolProp.fromProto(mImpl.getRtlAware());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static Padding fromProto(@NonNull ModifiersProto.Padding proto) {
+ return new Padding(proto, null);
+ }
+
+ @NonNull
+ ModifiersProto.Padding toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link Padding} */
+ public static final class Builder {
+ private final ModifiersProto.Padding.Builder mImpl = ModifiersProto.Padding.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1120275440);
+
+ public Builder() {}
+
+ /**
+ * Sets the padding on the end of the content, depending on the layout direction, in DP and
+ * the value of "rtl_aware".
+ */
+ @NonNull
+ public Builder setEnd(@NonNull DpProp end) {
+ mImpl.setEnd(end.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(end.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the padding on the start of the content, depending on the layout direction, in DP and
+ * the value of "rtl_aware".
+ */
+ @NonNull
+ public Builder setStart(@NonNull DpProp start) {
+ mImpl.setStart(start.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(start.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the padding at the top, in DP.
+ */
+ @NonNull
+ public Builder setTop(@NonNull DpProp top) {
+ mImpl.setTop(top.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(top.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the padding at the bottom, in DP.
+ */
+ @NonNull
+ public Builder setBottom(@NonNull DpProp bottom) {
+ mImpl.setBottom(bottom.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(bottom.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets whether the start/end padding is aware of RTL support. If true, the values for
+ * start/end will follow the layout direction (i.e. start will refer to the right hand side of
+ * the container if the device is using an RTL locale). If false, start/end will always map to
+ * left/right, accordingly.
+ */
+ @NonNull
+ public Builder setRtlAware(@NonNull BoolProp rtlAware) {
+ mImpl.setRtlAware(rtlAware.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(rtlAware.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets whether the start/end padding is aware of RTL support. If true, the values for
+ * start/end will follow the layout direction (i.e. start will refer to the right hand side of
+ * the container if the device is using an RTL locale). If false, start/end will always map to
+ * left/right, accordingly.
+ */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @NonNull
+ public Builder setRtlAware(boolean rtlAware) {
+ mImpl.setRtlAware(TypesProto.BoolProp.newBuilder().setValue(rtlAware));
+ mFingerprint.recordPropertyUpdate(5, Boolean.hashCode(rtlAware));
+ return this;
+ }
+
+ /**
+ * Sets the padding for all sides of the content, in DP.
+ */
+ @NonNull
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public Builder setAll(@NonNull DpProp value) {
+ return setStart(value).setEnd(value).setTop(value).setBottom(value);
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public Padding build() {
+ return new Padding(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A modifier to apply a border around an element. */
+ public static final class Border {
+ private final ModifiersProto.Border mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ Border(ModifiersProto.Border impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the width of the border, in DP. Intended for testing purposes only. */
+ @Nullable
+ public DpProp getWidth() {
+ if (mImpl.hasWidth()) {
+ return DpProp.fromProto(mImpl.getWidth());
+ } else {
+ return null;
+ }
+ }
+
+ /** Gets the color of the border. Intended for testing purposes only. */
+ @Nullable
+ public ColorProp getColor() {
+ if (mImpl.hasColor()) {
+ return ColorProp.fromProto(mImpl.getColor());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static Border fromProto(@NonNull ModifiersProto.Border proto) {
+ return new Border(proto, null);
+ }
+
+ @NonNull
+ ModifiersProto.Border toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link Border} */
+ public static final class Builder {
+ private final ModifiersProto.Border.Builder mImpl = ModifiersProto.Border.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(2085330827);
+
+ public Builder() {}
+
+ /**
+ * Sets the width of the border, in DP.
+ */
+ @NonNull
+ public Builder setWidth(@NonNull DpProp width) {
+ mImpl.setWidth(width.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(width.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the color of the border.
+ */
+ @NonNull
+ public Builder setColor(@NonNull ColorProp color) {
+ mImpl.setColor(color.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(color.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public Border build() {
+ return new Border(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** The corner of a {@link androidx.wear.tiles.LayoutElementBuilders.Box} element. */
+ public static final class Corner {
+ private final ModifiersProto.Corner mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ Corner(ModifiersProto.Corner impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the radius of the corner in DP. Intended for testing purposes only. */
+ @Nullable
+ public DpProp getRadius() {
+ if (mImpl.hasRadius()) {
+ return DpProp.fromProto(mImpl.getRadius());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static Corner fromProto(@NonNull ModifiersProto.Corner proto) {
+ return new Corner(proto, null);
+ }
+
+ @NonNull
+ ModifiersProto.Corner toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link Corner} */
+ public static final class Builder {
+ private final ModifiersProto.Corner.Builder mImpl = ModifiersProto.Corner.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-623478338);
+
+ public Builder() {}
+
+ /**
+ * Sets the radius of the corner in DP.
+ */
+ @NonNull
+ public Builder setRadius(@NonNull DpProp radius) {
+ mImpl.setRadius(radius.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(radius.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public Corner build() {
+ return new Corner(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A modifier to apply a background to an element. */
+ public static final class Background {
+ private final ModifiersProto.Background mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ Background(ModifiersProto.Background impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets the background color for this element. If not defined, defaults to being transparent.
+ * Intended for testing purposes only.
+ */
+ @Nullable
+ public ColorProp getColor() {
+ if (mImpl.hasColor()) {
+ return ColorProp.fromProto(mImpl.getColor());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the corner properties of this element. This only affects the drawing of this element if
+ * it has a background color or border. If not defined, defaults to having a square corner.
+ * Intended for testing purposes only.
+ */
+ @Nullable
+ public Corner getCorner() {
+ if (mImpl.hasCorner()) {
+ return Corner.fromProto(mImpl.getCorner());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static Background fromProto(@NonNull ModifiersProto.Background proto) {
+ return new Background(proto, null);
+ }
+
+ @NonNull
+ ModifiersProto.Background toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link Background} */
+ public static final class Builder {
+ private final ModifiersProto.Background.Builder mImpl =
+ ModifiersProto.Background.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(374507572);
+
+ public Builder() {}
+
+ /**
+ * Sets the background color for this element. If not defined, defaults to being transparent.
+ */
+ @NonNull
+ public Builder setColor(@NonNull ColorProp color) {
+ mImpl.setColor(color.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(color.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the corner properties of this element. This only affects the drawing of this element
+ * if it has a background color or border. If not defined, defaults to having a square corner.
+ */
+ @NonNull
+ public Builder setCorner(@NonNull Corner corner) {
+ mImpl.setCorner(corner.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(corner.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public Background build() {
+ return new Background(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /**
+ * Metadata about an element. For use by libraries building higher-level components only. This can
+ * be used to track component metadata.
+ */
+ public static final class ElementMetadata {
+ private final ModifiersProto.ElementMetadata mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ ElementMetadata(
+ ModifiersProto.ElementMetadata impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets property describing the element with which it is associated. For use by libraries
+ * building higher-level components only. This can be used to track component metadata.
+ */
+ @NonNull
+ public byte[] getTagData() {
+ return mImpl.getTagData().toByteArray();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static ElementMetadata fromProto(@NonNull ModifiersProto.ElementMetadata proto) {
+ return new ElementMetadata(proto, null);
+ }
+
+ /**
+ * Returns the internal proto instance.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public ModifiersProto.ElementMetadata toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link ElementMetadata} */
+ public static final class Builder {
+ private final ModifiersProto.ElementMetadata.Builder mImpl =
+ ModifiersProto.ElementMetadata.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-589294723);
+
+ public Builder() {}
+
+ /**
+ * Sets property describing the element with which it is associated. For use by libraries
+ * building higher-level components only. This can be used to track component metadata.
+ */
+ @NonNull
+ public Builder setTagData(@NonNull byte[] tagData) {
+ mImpl.setTagData(ByteString.copyFrom(tagData));
+ mFingerprint.recordPropertyUpdate(1, Arrays.hashCode(tagData));
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public ElementMetadata build() {
+ return new ElementMetadata(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /**
+ * {@link Modifiers} for an element. These may change the way they are drawn (e.g. {@link Padding}
+ * or {@link Background}), or change their behaviour (e.g. {@link Clickable}, or {@link
+ * Semantics}).
+ */
+ public static final class Modifiers {
+ private final ModifiersProto.Modifiers mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ Modifiers(ModifiersProto.Modifiers impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets the clickable property of the modified element. It allows its wrapped element to have
+ * actions associated with it, which will be executed when the element is tapped. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public Clickable getClickable() {
+ if (mImpl.hasClickable()) {
+ return Clickable.fromProto(mImpl.getClickable());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the semantics of the modified element. This can be used to add metadata to the modified
+ * element (eg. screen reader content descriptions). Intended for testing purposes only.
+ */
+ @Nullable
+ public Semantics getSemantics() {
+ if (mImpl.hasSemantics()) {
+ return Semantics.fromProto(mImpl.getSemantics());
+ } else {
+ return null;
+ }
+ }
+
+ /** Gets the padding of the modified element. Intended for testing purposes only. */
+ @Nullable
+ public Padding getPadding() {
+ if (mImpl.hasPadding()) {
+ return Padding.fromProto(mImpl.getPadding());
+ } else {
+ return null;
+ }
+ }
+
+ /** Gets the border of the modified element. Intended for testing purposes only. */
+ @Nullable
+ public Border getBorder() {
+ if (mImpl.hasBorder()) {
+ return Border.fromProto(mImpl.getBorder());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the background (with optional corner radius) of the modified element. Intended for
+ * testing purposes only.
+ */
+ @Nullable
+ public Background getBackground() {
+ if (mImpl.hasBackground()) {
+ return Background.fromProto(mImpl.getBackground());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets metadata about an element. For use by libraries building higher-level components only.
+ * This can be used to track component metadata.
+ */
+ @Nullable
+ public ElementMetadata getMetadata() {
+ if (mImpl.hasMetadata()) {
+ return ElementMetadata.fromProto(mImpl.getMetadata());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ /**
+ * Creates a new wrapper instance from the proto. Intended for testing purposes only. An object
+ * created using this method can't be added to any other wrapper.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public static Modifiers fromProto(@NonNull ModifiersProto.Modifiers proto) {
+ return new Modifiers(proto, null);
+ }
+
+ /**
+ * Returns the internal proto instance.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public ModifiersProto.Modifiers toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link Modifiers} */
+ public static final class Builder {
+ private final ModifiersProto.Modifiers.Builder mImpl = ModifiersProto.Modifiers.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-170942531);
+
+ public Builder() {}
+
+ /**
+ * Sets the clickable property of the modified element. It allows its wrapped element to have
+ * actions associated with it, which will be executed when the element is tapped.
+ */
+ @NonNull
+ public Builder setClickable(@NonNull Clickable clickable) {
+ mImpl.setClickable(clickable.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(clickable.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the semantics of the modified element. This can be used to add metadata to the
+ * modified element (eg. screen reader content descriptions).
+ */
+ @NonNull
+ public Builder setSemantics(@NonNull Semantics semantics) {
+ mImpl.setSemantics(semantics.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(semantics.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Sets the padding of the modified element. */
+ @NonNull
+ public Builder setPadding(@NonNull Padding padding) {
+ mImpl.setPadding(padding.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(padding.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Sets the border of the modified element. */
+ @NonNull
+ public Builder setBorder(@NonNull Border border) {
+ mImpl.setBorder(border.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(border.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Sets the background (with optional corner radius) of the modified element. */
+ @NonNull
+ public Builder setBackground(@NonNull Background background) {
+ mImpl.setBackground(background.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(background.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets metadata about an element. For use by libraries building higher-level components only.
+ * This can be used to track component metadata.
+ */
+ @NonNull
+ public Builder setMetadata(@NonNull ElementMetadata metadata) {
+ mImpl.setMetadata(metadata.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 6, checkNotNull(metadata.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public Modifiers build() {
+ return new Modifiers(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /**
+ * {@link Modifiers} that can be used with ArcLayoutElements. These may change the way they are
+ * drawn, or change their behaviour.
+ */
+ public static final class ArcModifiers {
+ private final ModifiersProto.ArcModifiers mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ ArcModifiers(ModifiersProto.ArcModifiers impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets allows its wrapped element to have actions associated with it, which will be executed
+ * when the element is tapped. Intended for testing purposes only.
+ */
+ @Nullable
+ public Clickable getClickable() {
+ if (mImpl.hasClickable()) {
+ return Clickable.fromProto(mImpl.getClickable());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets adds metadata for the modified element, for example, screen reader content descriptions.
+ * Intended for testing purposes only.
+ */
+ @Nullable
+ public Semantics getSemantics() {
+ if (mImpl.hasSemantics()) {
+ return Semantics.fromProto(mImpl.getSemantics());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static ArcModifiers fromProto(@NonNull ModifiersProto.ArcModifiers proto) {
+ return new ArcModifiers(proto, null);
+ }
+
+ /**
+ * Returns the internal proto instance.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public ModifiersProto.ArcModifiers toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link ArcModifiers} */
+ public static final class Builder {
+ private final ModifiersProto.ArcModifiers.Builder mImpl =
+ ModifiersProto.ArcModifiers.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1648736168);
+
+ public Builder() {}
+
+ /**
+ * Sets allows its wrapped element to have actions associated with it, which will be executed
+ * when the element is tapped.
+ */
+ @NonNull
+ public Builder setClickable(@NonNull Clickable clickable) {
+ mImpl.setClickable(clickable.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(clickable.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets adds metadata for the modified element, for example, screen reader content
+ * descriptions.
+ */
+ @NonNull
+ public Builder setSemantics(@NonNull Semantics semantics) {
+ mImpl.setSemantics(semantics.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(semantics.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public ArcModifiers build() {
+ return new ArcModifiers(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /**
+ * {@link Modifiers} that can be used with {@link androidx.wear.tiles.LayoutElementBuilders.Span}
+ * elements. These may change the way they are drawn, or change their behaviour.
+ */
+ public static final class SpanModifiers {
+ private final ModifiersProto.SpanModifiers mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ SpanModifiers(ModifiersProto.SpanModifiers impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets allows its wrapped element to have actions associated with it, which will be executed
+ * when the element is tapped. Intended for testing purposes only.
+ */
+ @Nullable
+ public Clickable getClickable() {
+ if (mImpl.hasClickable()) {
+ return Clickable.fromProto(mImpl.getClickable());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static SpanModifiers fromProto(@NonNull ModifiersProto.SpanModifiers proto) {
+ return new SpanModifiers(proto, null);
+ }
+
+ /**
+ * Returns the internal proto instance.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public ModifiersProto.SpanModifiers toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link SpanModifiers} */
+ public static final class Builder {
+ private final ModifiersProto.SpanModifiers.Builder mImpl =
+ ModifiersProto.SpanModifiers.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1318656482);
+
+ public Builder() {}
+
+ /**
+ * Sets allows its wrapped element to have actions associated with it, which will be executed
+ * when the element is tapped.
+ */
+ @NonNull
+ public Builder setClickable(@NonNull Clickable clickable) {
+ mImpl.setClickable(clickable.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(clickable.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public SpanModifiers build() {
+ return new SpanModifiers(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+}
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ResourceBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ResourceBuilders.java
new file mode 100644
index 0000000..8e23d72
--- /dev/null
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ResourceBuilders.java
@@ -0,0 +1,414 @@
+/*
+ * Copyright 2021-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.
+ */
+
+package androidx.wear.protolayout;
+
+import static androidx.annotation.Dimension.PX;
+
+import android.annotation.SuppressLint;
+import androidx.annotation.Dimension;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.ProtoLayoutExperimental;
+import androidx.wear.protolayout.proto.ResourceProto;
+import androidx.wear.protolayout.protobuf.ByteString;
+import androidx.wear.protolayout.protobuf.InvalidProtocolBufferException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/** Builders for the resources for a layout. */
+public final class ResourceBuilders {
+ private ResourceBuilders() {}
+
+ /**
+ * Format describing the contents of an image data byte array.
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @IntDef({IMAGE_FORMAT_UNDEFINED, IMAGE_FORMAT_RGB_565})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ImageFormat {}
+
+ /** An undefined image format. */
+ public static final int IMAGE_FORMAT_UNDEFINED = 0;
+
+ /**
+ * An image format where each pixel is stored on 2 bytes, with red using 5 bits, green using 6
+ * bits and blue using 5 bits of precision.
+ */
+ public static final int IMAGE_FORMAT_RGB_565 = 1;
+
+ /** An image resource which maps to an Android drawable by resource ID. */
+ public static final class AndroidImageResourceByResId {
+ private final ResourceProto.AndroidImageResourceByResId mImpl;
+
+ private AndroidImageResourceByResId(ResourceProto.AndroidImageResourceByResId impl) {
+ this.mImpl = impl;
+ }
+
+ /**
+ * Gets the Android resource ID of this image. This must refer to a drawable under R.drawable.
+ * Intended for testing purposes only.
+ */
+ @DrawableRes
+ public int getResourceId() {
+ return mImpl.getResourceId();
+ }
+
+ @NonNull
+ static AndroidImageResourceByResId fromProto(
+ @NonNull ResourceProto.AndroidImageResourceByResId proto) {
+ return new AndroidImageResourceByResId(proto);
+ }
+
+ @NonNull
+ ResourceProto.AndroidImageResourceByResId toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link AndroidImageResourceByResId} */
+ public static final class Builder {
+ private final ResourceProto.AndroidImageResourceByResId.Builder mImpl =
+ ResourceProto.AndroidImageResourceByResId.newBuilder();
+
+ public Builder() {}
+
+ /**
+ * Sets the Android resource ID of this image. This must refer to a drawable under R.drawable.
+ */
+ @NonNull
+ public Builder setResourceId(@DrawableRes int resourceId) {
+ mImpl.setResourceId(resourceId);
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public AndroidImageResourceByResId build() {
+ return AndroidImageResourceByResId.fromProto(mImpl.build());
+ }
+ }
+ }
+
+ /**
+ * An image resource whose data is fully inlined, with no dependency on a system or app resource.
+ */
+ public static final class InlineImageResource {
+ private final ResourceProto.InlineImageResource mImpl;
+
+ private InlineImageResource(ResourceProto.InlineImageResource impl) {
+ this.mImpl = impl;
+ }
+
+ /** Gets the byte array representing the image. Intended for testing purposes only. */
+ @NonNull
+ public byte[] getData() {
+ return mImpl.getData().toByteArray();
+ }
+
+ /**
+ * Gets the native width of the image, in pixels. Only required for formats (e.g.
+ * IMAGE_FORMAT_RGB_565) where the image data does not include size. Intended for testing
+ * purposes only.
+ */
+ @Dimension(unit = PX)
+ public int getWidthPx() {
+ return mImpl.getWidthPx();
+ }
+
+ /**
+ * Gets the native height of the image, in pixels. Only required for formats (e.g.
+ * IMAGE_FORMAT_RGB_565) where the image data does not include size. Intended for testing
+ * purposes only.
+ */
+ @Dimension(unit = PX)
+ public int getHeightPx() {
+ return mImpl.getHeightPx();
+ }
+
+ /**
+ * Gets the format of the byte array data representing the image. May be left unspecified or set
+ * to IMAGE_FORMAT_UNDEFINED in which case the platform will attempt to extract this from the
+ * raw image data. If the platform does not support the format, the image will not be decoded or
+ * displayed. Intended for testing purposes only.
+ */
+ @ImageFormat
+ public int getFormat() {
+ return mImpl.getFormat().getNumber();
+ }
+
+ @NonNull
+ static InlineImageResource fromProto(@NonNull ResourceProto.InlineImageResource proto) {
+ return new InlineImageResource(proto);
+ }
+
+ @NonNull
+ ResourceProto.InlineImageResource toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link InlineImageResource} */
+ public static final class Builder {
+ private final ResourceProto.InlineImageResource.Builder mImpl =
+ ResourceProto.InlineImageResource.newBuilder();
+
+ public Builder() {}
+
+ /** Sets the byte array representing the image. */
+ @NonNull
+ public Builder setData(@NonNull byte[] data) {
+ mImpl.setData(ByteString.copyFrom(data));
+ return this;
+ }
+
+ /**
+ * Sets the native width of the image, in pixels. Only required for formats (e.g.
+ * IMAGE_FORMAT_RGB_565) where the image data does not include size.
+ */
+ @NonNull
+ public Builder setWidthPx(@Dimension(unit = PX) int widthPx) {
+ mImpl.setWidthPx(widthPx);
+ return this;
+ }
+
+ /**
+ * Sets the native height of the image, in pixels. Only required for formats (e.g.
+ * IMAGE_FORMAT_RGB_565) where the image data does not include size.
+ */
+ @NonNull
+ public Builder setHeightPx(@Dimension(unit = PX) int heightPx) {
+ mImpl.setHeightPx(heightPx);
+ return this;
+ }
+
+ /**
+ * Sets the format of the byte array data representing the image. May be left unspecified or
+ * set to IMAGE_FORMAT_UNDEFINED in which case the platform will attempt to extract this from
+ * the raw image data. If the platform does not support the format, the image will not be
+ * decoded or displayed.
+ */
+ @NonNull
+ public Builder setFormat(@ImageFormat int format) {
+ mImpl.setFormat(ResourceProto.ImageFormat.forNumber(format));
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public InlineImageResource build() {
+ return InlineImageResource.fromProto(mImpl.build());
+ }
+ }
+ }
+
+ /**
+ * An image resource, which can be used by layouts. This holds multiple underlying resource types,
+ * which the underlying runtime will pick according to what it thinks is appropriate.
+ */
+ public static final class ImageResource {
+ private final ResourceProto.ImageResource mImpl;
+
+ private ImageResource(ResourceProto.ImageResource impl) {
+ this.mImpl = impl;
+ }
+
+ /**
+ * Gets an image resource that maps to an Android drawable by resource ID. Intended for testing
+ * purposes only.
+ */
+ @Nullable
+ public AndroidImageResourceByResId getAndroidResourceByResId() {
+ if (mImpl.hasAndroidResourceByResId()) {
+ return AndroidImageResourceByResId.fromProto(mImpl.getAndroidResourceByResId());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets an image resource that contains the image data inline. Intended for testing purposes
+ * only.
+ */
+ @Nullable
+ public InlineImageResource getInlineResource() {
+ if (mImpl.hasInlineResource()) {
+ return InlineImageResource.fromProto(mImpl.getInlineResource());
+ } else {
+ return null;
+ }
+ }
+
+ @NonNull
+ static ImageResource fromProto(@NonNull ResourceProto.ImageResource proto) {
+ return new ImageResource(proto);
+ }
+
+ @NonNull
+ ResourceProto.ImageResource toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link ImageResource} */
+ public static final class Builder {
+ private final ResourceProto.ImageResource.Builder mImpl =
+ ResourceProto.ImageResource.newBuilder();
+
+ public Builder() {}
+
+ /** Sets an image resource that maps to an Android drawable by resource ID. */
+ @NonNull
+ public Builder setAndroidResourceByResId(
+ @NonNull AndroidImageResourceByResId androidResourceByResId) {
+ mImpl.setAndroidResourceByResId(androidResourceByResId.toProto());
+ return this;
+ }
+
+ /** Sets an image resource that contains the image data inline. */
+ @NonNull
+ public Builder setInlineResource(@NonNull InlineImageResource inlineResource) {
+ mImpl.setInlineResource(inlineResource.toProto());
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public ImageResource build() {
+ return ImageResource.fromProto(mImpl.build());
+ }
+ }
+ }
+
+ /** The resources for a layout. */
+ public static final class Resources {
+ private final ResourceProto.Resources mImpl;
+
+ private Resources(ResourceProto.Resources impl) {
+ this.mImpl = impl;
+ }
+
+ /**
+ * Gets the version of this {@link Resources} instance.
+ *
+ * <p>Each tile specifies the version of resources it requires. After fetching a tile, the
+ * renderer will use the resources version specified by the tile to separately fetch the
+ * resources.
+ *
+ * <p>This value must match the version of the resources required by the tile for the tile to
+ * render successfully, and must match the resource version specified in {@link
+ * androidx.wear.tiles.RequestBuilders.ResourcesRequest} which triggered this request. Intended
+ * for testing purposes only.
+ */
+ @NonNull
+ public String getVersion() {
+ return mImpl.getVersion();
+ }
+
+ /**
+ * Gets a map of resource_ids to images, which can be used by layouts. Intended for testing
+ * purposes only.
+ */
+ @NonNull
+ public Map<String, ImageResource> getIdToImageMapping() {
+ Map<String, ImageResource> map = new HashMap<>();
+ for (Entry<String, ResourceProto.ImageResource> entry : mImpl.getIdToImageMap().entrySet()) {
+ map.put(entry.getKey(), ImageResource.fromProto(entry.getValue()));
+ }
+ return Collections.unmodifiableMap(map);
+ }
+
+ /** Converts to byte array representation. */
+ @NonNull
+ @ProtoLayoutExperimental
+ public byte[] toByteArray() {
+ return mImpl.toByteArray();
+ }
+
+ /** Converts from byte array representation. */
+ @SuppressWarnings("ProtoParseWithRegistry")
+ @Nullable
+ @ProtoLayoutExperimental
+ public static Resources fromByteArray(@NonNull byte[] byteArray) {
+ try {
+ return fromProto(ResourceProto.Resources.parseFrom(byteArray));
+ } catch (InvalidProtocolBufferException e) {
+ return null;
+ }
+ }
+
+ @NonNull
+ static Resources fromProto(@NonNull ResourceProto.Resources proto) {
+ return new Resources(proto);
+ }
+
+ /**
+ * Returns the internal proto instance.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public ResourceProto.Resources toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link Resources} */
+ public static final class Builder {
+ private final ResourceProto.Resources.Builder mImpl = ResourceProto.Resources.newBuilder();
+
+ public Builder() {}
+
+ /**
+ * Sets the version of this {@link Resources} instance.
+ *
+ * <p>Each tile specifies the version of resources it requires. After fetching a tile, the
+ * renderer will use the resources version specified by the tile to separately fetch the
+ * resources.
+ *
+ * <p>This value must match the version of the resources required by the tile for the tile to
+ * render successfully, and must match the resource version specified in {@link
+ * androidx.wear.tiles.RequestBuilders.ResourcesRequest} which triggered this request.
+ */
+ @NonNull
+ public Builder setVersion(@NonNull String version) {
+ mImpl.setVersion(version);
+ return this;
+ }
+
+ /** Adds an entry into a map of resource_ids to images, which can be used by layouts. */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @NonNull
+ public Builder addIdToImageMapping(@NonNull String id, @NonNull ImageResource image) {
+ mImpl.putIdToImage(id, image.toProto());
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public Resources build() {
+ return Resources.fromProto(mImpl.build());
+ }
+ }
+ }
+}
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/StateBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/StateBuilders.java
new file mode 100644
index 0000000..d29e831
--- /dev/null
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/StateBuilders.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2021-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.
+ */
+
+package androidx.wear.protolayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
+import androidx.wear.protolayout.proto.StateProto;
+
+/** Builders for state of a tile. */
+public final class StateBuilders {
+ private StateBuilders() {}
+
+ /** {@link State} information. */
+ public static final class State {
+ private final StateProto.State mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ State(StateProto.State impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the ID of the clickable that was last clicked. */
+ @NonNull
+ public String getLastClickableId() {
+ return mImpl.getLastClickableId();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static State fromProto(@NonNull StateProto.State proto) {
+ return new State(proto, null);
+ }
+
+ @NonNull
+ StateProto.State toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link State} */
+ public static final class Builder {
+ private final StateProto.State.Builder mImpl = StateProto.State.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(616326811);
+
+ public Builder() {}
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public State build() {
+ return new State(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+}
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TimelineBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TimelineBuilders.java
new file mode 100644
index 0000000..5ddacfc
--- /dev/null
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TimelineBuilders.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2021-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.
+ */
+
+package androidx.wear.protolayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.wear.protolayout.proto.TimelineProto;
+import androidx.wear.protolayout.LayoutElementBuilders.Layout;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Builders for a timeline with entries representing content that should be displayed within given
+ * time intervals.
+ */
+public final class TimelineBuilders {
+ private TimelineBuilders() {}
+
+ /** A time interval, typically used to describe the validity period of a {@link TimelineEntry}. */
+ public static final class TimeInterval {
+ private final TimelineProto.TimeInterval mImpl;
+
+ private TimeInterval(TimelineProto.TimeInterval impl) {
+ this.mImpl = impl;
+ }
+
+ /**
+ * Gets starting point of the time interval, in milliseconds since the Unix epoch. Intended for
+ * testing purposes only.
+ */
+ public long getStartMillis() {
+ return mImpl.getStartMillis();
+ }
+
+ /**
+ * Gets end point of the time interval, in milliseconds since the Unix epoch. Intended for
+ * testing purposes only.
+ */
+ public long getEndMillis() {
+ return mImpl.getEndMillis();
+ }
+
+ @NonNull
+ static TimeInterval fromProto(@NonNull TimelineProto.TimeInterval proto) {
+ return new TimeInterval(proto);
+ }
+
+ @NonNull
+ TimelineProto.TimeInterval toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link TimeInterval} */
+ public static final class Builder {
+ private final TimelineProto.TimeInterval.Builder mImpl =
+ TimelineProto.TimeInterval.newBuilder();
+
+ public Builder() {}
+
+ /** Sets starting point of the time interval, in milliseconds since the Unix epoch. */
+ @NonNull
+ public Builder setStartMillis(long startMillis) {
+ mImpl.setStartMillis(startMillis);
+ return this;
+ }
+
+ /** Sets end point of the time interval, in milliseconds since the Unix epoch. */
+ @NonNull
+ public Builder setEndMillis(long endMillis) {
+ mImpl.setEndMillis(endMillis);
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public TimeInterval build() {
+ return TimeInterval.fromProto(mImpl.build());
+ }
+ }
+ }
+
+ /** One piece of renderable content along with the time that it is valid for. */
+ public static final class TimelineEntry {
+ private final TimelineProto.TimelineEntry mImpl;
+
+ private TimelineEntry(TimelineProto.TimelineEntry impl) {
+ this.mImpl = impl;
+ }
+
+ /** Gets the validity period for this timeline entry. Intended for testing purposes only. */
+ @Nullable
+ public TimeInterval getValidity() {
+ if (mImpl.hasValidity()) {
+ return TimeInterval.fromProto(mImpl.getValidity());
+ } else {
+ return null;
+ }
+ }
+
+ /** Gets the contents of this timeline entry. Intended for testing purposes only. */
+ @Nullable
+ public Layout getLayout() {
+ if (mImpl.hasLayout()) {
+ return Layout.fromProto(mImpl.getLayout());
+ } else {
+ return null;
+ }
+ }
+
+ /** Returns the {@link TimelineEntry} object containing the given layout element. */
+ @NonNull
+ public static TimelineEntry fromLayoutElement(
+ @NonNull LayoutElementBuilders.LayoutElement layoutElement) {
+ return new Builder().setLayout(Layout.fromLayoutElement(layoutElement)).build();
+ }
+
+ @NonNull
+ static TimelineEntry fromProto(@NonNull TimelineProto.TimelineEntry proto) {
+ return new TimelineEntry(proto);
+ }
+
+ @NonNull
+ TimelineProto.TimelineEntry toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link TimelineEntry} */
+ public static final class Builder {
+ private final TimelineProto.TimelineEntry.Builder mImpl =
+ TimelineProto.TimelineEntry.newBuilder();
+
+ public Builder() {}
+
+ /** Sets the validity period for this timeline entry. */
+ @NonNull
+ public Builder setValidity(@NonNull TimeInterval validity) {
+ mImpl.setValidity(validity.toProto());
+ return this;
+ }
+
+ /** Sets the contents of this timeline entry. */
+ @NonNull
+ public Builder setLayout(@NonNull Layout layout) {
+ mImpl.setLayout(layout.toProto());
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public TimelineEntry build() {
+ return TimelineEntry.fromProto(mImpl.build());
+ }
+ }
+ }
+
+ /**
+ * A collection of {@link TimelineEntry} items.
+ *
+ * <p>{@link TimelineEntry} items can be used to update a layout on-screen at known times, without
+ * having to explicitly update a layout. This allows for cases where, say, a calendar can be used
+ * to show the next event, and automatically switch to showing the next event when one has passed.
+ *
+ * <p>The active {@link TimelineEntry} is switched, at most, once a minute. In the case where the
+ * validity periods of {@link TimelineEntry} items overlap, the item with the shortest* validity
+ * period will be shown. This allows a layout provider to show a "default" layout, and override it
+ * at set points without having to explicitly insert the default layout between the "override"
+ * layout.
+ */
+ public static final class Timeline {
+ private final TimelineProto.Timeline mImpl;
+
+ private Timeline(TimelineProto.Timeline impl) {
+ this.mImpl = impl;
+ }
+
+ /** Gets the entries in a timeline. Intended for testing purposes only. */
+ @NonNull
+ public List<TimelineEntry> getTimelineEntries() {
+ List<TimelineEntry> list = new ArrayList<>();
+ for (TimelineProto.TimelineEntry item : mImpl.getTimelineEntriesList()) {
+ list.add(TimelineEntry.fromProto(item));
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ /** Returns the {@link Timeline} object containing the given layout element. */
+ @NonNull
+ public static Timeline fromLayoutElement(
+ @NonNull LayoutElementBuilders.LayoutElement layoutElement) {
+ return new Builder().addTimelineEntry(TimelineEntry.fromLayoutElement(layoutElement)).build();
+ }
+
+ @NonNull
+ static Timeline fromProto(@NonNull TimelineProto.Timeline proto) {
+ return new Timeline(proto);
+ }
+
+ @NonNull
+ TimelineProto.Timeline toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link Timeline} */
+ public static final class Builder {
+ private final TimelineProto.Timeline.Builder mImpl = TimelineProto.Timeline.newBuilder();
+
+ public Builder() {}
+
+ /** Adds one item to the entries in a timeline. */
+ @NonNull
+ public Builder addTimelineEntry(@NonNull TimelineEntry timelineEntry) {
+ mImpl.addTimelineEntries(timelineEntry.toProto());
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public Timeline build() {
+ return Timeline.fromProto(mImpl.build());
+ }
+ }
+ }
+}
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TypeBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TypeBuilders.java
new file mode 100644
index 0000000..cb605fc
--- /dev/null
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TypeBuilders.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2021-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.
+ */
+
+package androidx.wear.protolayout;
+
+import android.annotation.SuppressLint;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.Fingerprint;
+import androidx.wear.protolayout.proto.TypesProto;
+
+/** Builders for extensible primitive types used by layout elements. */
+public final class TypeBuilders {
+ private TypeBuilders() {}
+
+ /** An int32 type. */
+ public static final class Int32Prop {
+ private final TypesProto.Int32Prop mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ Int32Prop(TypesProto.Int32Prop impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value. Intended for testing purposes only. */
+ public int getValue() {
+ return mImpl.getValue();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static Int32Prop fromProto(@NonNull TypesProto.Int32Prop proto) {
+ return new Int32Prop(proto, null);
+ }
+
+ @NonNull
+ TypesProto.Int32Prop toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link Int32Prop} */
+ public static final class Builder {
+ private final TypesProto.Int32Prop.Builder mImpl = TypesProto.Int32Prop.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1809132005);
+
+ public Builder() {}
+
+ /** Sets the value. */
+ @NonNull
+ public Builder setValue(int value) {
+ mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, value);
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public Int32Prop build() {
+ return new Int32Prop(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A string type. */
+ public static final class StringProp {
+ private final TypesProto.StringProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ StringProp(TypesProto.StringProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value. Intended for testing purposes only. */
+ @NonNull
+ public String getValue() {
+ return mImpl.getValue();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static StringProp fromProto(@NonNull TypesProto.StringProp proto) {
+ return new StringProp(proto, null);
+ }
+
+ @NonNull
+ TypesProto.StringProp toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link StringProp} */
+ public static final class Builder {
+ private final TypesProto.StringProp.Builder mImpl = TypesProto.StringProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-319420356);
+
+ public Builder() {}
+
+ /** Sets the value. */
+ @NonNull
+ public Builder setValue(@NonNull String value) {
+ mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, value.hashCode());
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public StringProp build() {
+ return new StringProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A float type. */
+ public static final class FloatProp {
+ private final TypesProto.FloatProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ FloatProp(TypesProto.FloatProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value. Intended for testing purposes only. */
+ public float getValue() {
+ return mImpl.getValue();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static FloatProp fromProto(@NonNull TypesProto.FloatProp proto) {
+ return new FloatProp(proto, null);
+ }
+
+ @NonNull
+ TypesProto.FloatProp toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link FloatProp} */
+ public static final class Builder {
+ private final TypesProto.FloatProp.Builder mImpl = TypesProto.FloatProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(399943127);
+
+ public Builder() {}
+
+ /** Sets the value. */
+ @NonNull
+ public Builder setValue(float value) {
+ mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, Float.floatToIntBits(value));
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public FloatProp build() {
+ return new FloatProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A boolean type. */
+ public static final class BoolProp {
+ private final TypesProto.BoolProp mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ BoolProp(TypesProto.BoolProp impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the value. Intended for testing purposes only. */
+ public boolean getValue() {
+ return mImpl.getValue();
+ }
+
+ /**
+ * Get the fingerprint for this object, or null if unknown.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ @NonNull
+ static BoolProp fromProto(@NonNull TypesProto.BoolProp proto) {
+ return new BoolProp(proto, null);
+ }
+
+ @NonNull
+ TypesProto.BoolProp toProto() {
+ return mImpl;
+ }
+
+ /** Builder for {@link BoolProp} */
+ public static final class Builder {
+ private final TypesProto.BoolProp.Builder mImpl = TypesProto.BoolProp.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-278424864);
+
+ public Builder() {}
+
+ /** Sets the value. */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @NonNull
+ public Builder setValue(boolean value) {
+ mImpl.setValue(value);
+ mFingerprint.recordPropertyUpdate(1, Boolean.hashCode(value));
+ return this;
+ }
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public BoolProp build() {
+ return new BoolProp(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+}